/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : bsp_led.c
作者 : 左忠凯
版本 : V1.0
描述 : 串口驱动文件。
其他 : 无
论坛 : www.wtmembed.com
日志 : 初版V1.0 2019/1/15 左忠凯创建
***************************************************************/
#include "bsp_uart.h"
#include "bsp_int.h"
#include "bsp_led.h"
void uart1_irqhandler(void);
/*
* @description : 初始化串口1,波特率为115200
* @param : 无
* @return : 无
*/
void uart_init(void)
{
/* 1、初始化串口IO */
uart_io_init();
/* 2、初始化UART1 */
uart_disable(UART1); /* 先关闭UART1 */
uart_softreset(UART1); /* 软件复位UART1 */
UART1->UCR1 = 0; /* 先清除UCR1寄存器 */
/*
* 设置UART的UCR1寄存器,关闭自动波特率
* bit14: 0 关闭自动波特率检测,我们自己设置波特率
*/
UART1->UCR1 &= ~(1<<14);
/*
* 设置UART的UCR2寄存器,设置内容包括字长,停止位,校验模式,关闭RTS硬件流控
* bit14: 1 忽略RTS引脚
* bit8: 0 关闭奇偶校验
* bit6: 0 1位停止位
* bit5: 1 8位数据位
* bit2: 1 打开发送
* bit1: 1 打开接收
*/
UART1->UCR2 |= (1<<14) | (1<<5) | (1<<2) | (1<<1);
/*
* UART1的UCR3寄存器
* bit2: 1 必须设置为1!参考IMX6ULL参考手册3624页
*/
UART1->UCR3 |= 1<<2;
/*
* UART1的UCR4寄存器
* bit0 设置为1,使能RDR interrupt
*/
UART1->UCR4 |= 1<<0;
/*
* 中断服务函数
*/
GIC_EnableIRQ(UART1_IRQn); /* 使能GIC中对应的中断 */
system_register_irqhandler(UART1_IRQn, (system_irq_handler_t)uart1_irqhandler, NULL); /* 注册中断服务函数 */
/*
* 设置波特率
* 波特率计算公式:Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1))
* 如果要设置波特率为115200,那么可以使用如下参数:
* Ref Freq = 80M 也就是寄存器UFCR的bit9:7=101, 表示1分频
* UBMR = 3124
* UBIR = 71
* 因此波特率= 80000000/(16 * (3124+1)/(71+1))=80000000/(16 * 3125/72) = (80000000*72) / (16*3125) = 115200
*/
UART1->UFCR = 5<<7; //ref freq等于ipg_clk/1=80Mhz
UART1->UBIR = 71;
UART1->UBMR = 3124;
#if 0
uart_setbaudrate(UART1, 115200, 80000000); /* 设置波特率 */
#endif
/* 使能串口 */
uart_enable(UART1);
}
/*
* @description : 初始化串口1所使用的IO引脚
* @param : 无
* @return : 无
*/
void uart_io_init(void)
{
/* 1、初始化IO复用
* UART1_RXD -> UART1_TX_DATA
* UART1_TXD -> UART1_RX_DATA
*/
IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0); /* 复用为UART1_TX */
IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0); /* 复用为UART1_RX */
/* 2、配置UART1_TX_DATA、UART1_RX_DATA的IO属性
*bit 16:0 HYS关闭
*bit [15:14]: 00 默认100K下拉
*bit [13]: 0 keeper功能
*bit [12]: 1 pull/keeper使能
*bit [11]: 0 关闭开路输出
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 110 驱动能力R0/6
*bit [0]: 0 低转换率
*/
IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0);
IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10B0);
}
/*
* @description : 波特率计算公式,
* 可以用此函数计算出指定串口对应的UFCR,
* UBIR和UBMR这三个寄存器的值
* @param - base : 要计算的串口。
* @param - baudrate : 要使用的波特率。
* @param - srcclock_hz :串口时钟源频率,单位Hz
* @return : 无
*/
void uart_setbaudrate(UART_Type *base, unsigned int baudrate, unsigned int srcclock_hz)
{
uint32_t numerator = 0u; //分子
uint32_t denominator = 0U; //分母
uint32_t divisor = 0U;
uint32_t refFreqDiv = 0U;
uint32_t divider = 1U;
uint64_t baudDiff = 0U;
uint64_t tempNumerator = 0U;
uint32_t tempDenominator = 0u;
/* get the approximately maximum divisor */
numerator = srcclock_hz;
denominator = baudrate << 4;
divisor = 1;
while (denominator != 0)
{
divisor = denominator;
denominator = numerator % denominator;
numerator = divisor;
}
numerator = srcclock_hz / divisor;
denominator = (baudrate << 4) / divisor;
/* numerator ranges from 1 ~ 7 * 64k */
/* denominator ranges from 1 ~ 64k */
if ((numerator > (UART_UBIR_INC_MASK * 7)) || (denominator > UART_UBIR_INC_MASK))
{
uint32_t m = (numerator - 1) / (UART_UBIR_INC_MASK * 7) + 1;
uint32_t n = (denominator - 1) / UART_UBIR_INC_MASK + 1;
uint32_t max = m > n ? m : n;
numerator /= max;
denominator /= max;
if (0 == numerator)
{
numerator = 1;
}
if (0 == denominator)
{
denominator = 1;
}
}
divider = (numerator - 1) / UART_UBIR_INC_MASK + 1;
switch (divider)
{
case 1:
refFreqDiv = 0x05;
break;
case 2:
refFreqDiv = 0x04;
break;
case 3:
refFreqDiv = 0x03;
break;
case 4:
refFreqDiv = 0x02;
break;
case 5:
refFreqDiv = 0x01;
break;
case 6:
refFreqDiv = 0x00;
break;
case 7:
refFreqDiv = 0x06;
break;
default:
refFreqDiv = 0x05;
break;
}
/* Compare the difference between baudRate_Bps and calculated baud rate.
* Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)).
* baudDiff = (srcClock_Hz/divider)/( 16 * ((numerator / divider)/ denominator).
*/
tempNumerator = srcclock_hz;
tempDenominator = (numerator << 4);
divisor = 1;
/* get the approximately maximum divisor */
while (tempDenominator != 0)
{
divisor = tempDenominator;
tempDenominator = tempNumerator % tempDenominator;
tempNumerator = divisor;
}
tempNumerator = srcclock_hz / divisor;
tempDenominator = (numerator << 4) / divisor;
baudDiff = (tempNumerator * denominator) / tempDenominator;
baudDiff = (baudDiff >= baudrate) ? (baudDiff - baudrate) : (baudrate - baudDiff);
if (baudDiff < (baudrate / 100) * 3)
{
base->UFCR &= ~UART_UFCR_RFDIV_MASK;
base->UFCR |= UART_UFCR_RFDIV(refFreqDiv);
base->UBIR = UART_UBIR_INC(denominator - 1); //要先写UBIR寄存器,然后在写UBMR寄存器,3592页
base->UBMR = UART_UBMR_MOD(numerator / divider - 1);
}
}
/*
* @description : 关闭指定的UART
* @param - base: 要关闭的UART
* @return : 无
*/
void uart_disable(UART_Type *base)
{
base->UCR1 &= ~(1<<0);
}
/*
* @description : 打开指定的UART
* @param - base: 要打开的UART
* @return : 无
*/
void uart_enable(UART_Type *base)
{
base->UCR1 |= (1<<0);
}
/*
* @description : 复位指定的UART
* @param - base: 要复位的UART
* @return : 无
*/
void uart_softreset(UART_Type *base)
{
base->UCR2 &= ~(1<<0); /* UCR2的bit0为0,复位UART */
while((base->UCR2 & 0x1) == 0); /* 等待复位完成 */
}
/*
* @description : 发送一个字符
* @param - c : 要发送的字符
* @return : 无
*/
void putc(unsigned char c)
{
while(((UART1->USR2 >> 3) &0X01) == 0);/* 等待上一次发送完成 */
UART1->UTXD = c & 0XFF; /* 发送数据 */
}
/*
* @description : 发送一个字符串
* @param - str : 要发送的字符串
* @return : 无
*/
void puts(char *str)
{
char *p = str;
while(*p)
putc(*p++);
}
/*
* @description : 接收一个字符
* @param : 无
* @return : 接收到的字符
*/
unsigned char getc(void)
{
while((UART1->USR2 & 0x1) == 0);/* 等待接收完成 */
return UART1->URXD; /* 返回接收到的数据 */
}
void uart1_irqhandler(void)
{
unsigned char data = 0;
static int state=0;
if ((UART1->USR2 & 0X1) == 1)
{
UART1->USR2 &= ~(1<<0);
dat
imx6ull裸机例程之uart中断(正点原子裸机例程修改)
需积分: 0 128 浏览量
更新于2024-02-21
收藏 355KB ZIP 举报
标题中的“imx6ull裸机例程之uart中断(正点原子裸机例程修改)”指的是在基于NXP i.MX6ULL处理器的裸机环境下,进行UART(通用异步收发传输器)中断的编程实例。在这个过程中,开发者通常会参考正点原子提供的基础教程或代码示例,并根据自己的开发环境进行相应的调整。裸机编程意味着不依赖任何操作系统,直接与硬件交互,因此需要对底层硬件和驱动程序有深入理解。
描述中的“makefile里面的LIBPATH需要修改(我交叉编译器路径与正点原子不一样)”提到了一个关键步骤。在Linux或类似的系统中,`makefile`用于自动化构建过程,包括编译、链接等步骤。由于用户的交叉编译器路径与正点原子提供的示例不同,因此需要更新`makefile`中的`LIBPATH`变量,以确保编译器能找到正确的库文件。交叉编译器是为不同架构的目标平台(如i.MX6ULL的ARM Cortex-A7)编译代码的工具,其路径通常不包含在标准系统路径中。
在进行UART中断实验时,我们需要了解以下几个关键知识点:
1. **UART接口**:UART是一种串行通信接口,广泛用于设备间的短距离通信。它通过数据线发送和接收数据,通常包括TX(发送)和RX(接收)两条线,还可以有额外的控制线如CTS/RTS(清除发送/请求发送)用于流控。
2. **中断处理**:中断是处理器响应外部事件的方式,当UART接收到数据或完成发送时,会触发中断。中断处理程序负责处理这些事件,通常包括读取接收缓冲区、清除接收标志或向发送缓冲区写入新数据。
3. **配置UART**:在裸机编程中,需要初始化UART控制器的寄存器,设置波特率、数据位数、停止位和奇偶校验等参数。这通常通过访问特定的内存地址来完成。
4. **中断使能**:为了启用UART中断,需要在适当的寄存器中设置相应的标志,允许处理器在特定事件发生时暂停当前任务并执行中断服务程序。
5. **交叉编译器**:由于i.MX6ULL是基于ARM架构的,开发PC上通常运行的是x86架构的系统,所以需要使用交叉编译器将源代码编译成适用于目标平台的二进制文件。
6. **Makefile**:Makefile是一个描述编译规则的文件,其中`LIBPATH`定义了库文件的位置。修改`LIBPATH`以指向正确的交叉编译器库路径,确保编译顺利进行。
7. **裸机编程实践**:在实践中,开发者需要编写中断服务程序,这个程序会在UART中断发生时执行,处理数据的收发。同时,还需要考虑中断的优先级和嵌套,以及中断的关闭和恢复,以确保系统稳定运行。
这个实验涵盖了嵌入式系统、UART通信、中断处理和交叉编译等多个重要概念,对于理解和掌握i.MX6ULL平台的裸机编程具有重要意义。通过这个实验,开发者可以深入学习到如何在没有操作系统支持的情况下,有效地利用硬件资源进行通信和事件处理。
拱-卒
- 粉丝: 169
- 资源: 6
最新资源
- SMC真空气动元件样本.pdf
- TBI导轨样本.pdf
- 机械设计真空吸附滑台取料机sw18可编辑非常好的设计图纸100%好用.zip
- 机械设计直线电机双动子贴膜摆盘机step非常好的设计图纸100%好用.zip
- matlab学习的成长心得
- 机械设计载盘试偏光片贴合机step非常好的设计图纸100%好用.zip
- CPC导轨资料.pdf
- kuka机器人_KR30-3各轴分解图以及保养.pdf
- 安川ES165爆炸图.pdf
- 德国kammerer丝杠.pdf
- TBI样本.pdf
- 德国制造带给我们的启示.pdf
- 滚珠螺旋传动设计基础.pdf
- 滚珠丝杠基础知识.ppt
- 三协滚珠丝杆介绍.pdf
- 莱恩.PDF