1. 参考 《外设的初始化》文档
主要分为如下几个部分:
- 使能外设的时钟信号
- 设置外设的引脚复用与 PAD
- 设置外设初始化参数 使能外设
2. 核心代码片段
1. 串口初始化
// 实际上是 RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, DISABLE);
// 先关闭 PWM_UART 的时钟。
// 官方demo里面对于GPIO引脚均如此使用
UART_DeInit(PWM_UART);
/* turn on UART1 clock */
RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, ENABLE);
/* pinmux config 引脚复用配置*/
Pinmux_Config(PWM_UART_TX_PIN, UART1_TX);
Pinmux_Config(PWM_UART_RX_PIN, UART1_RX);
/* pad config 配置引脚的pad状态 */
Pad_Config(PWM_UART_TX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW);
Pad_Config(PWM_UART_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW);
/* uart init 初始化uart参数 */
UART_InitTypeDef uartInitStruct;
UART_StructInit(&uartInitStruct);
// 波特率说明: 9600Hz 8bit
uartInitStruct.ovsr_adj = 0x24A;
uartInitStruct.div = 271;
uartInitStruct.ovsr = 10;
uartInitStruct.parity = UART_PARITY_NO_PARTY;
// 在桢结尾传输2个停止位
uartInitStruct.stopBits = UART_STOP_BITS_2;
uartInitStruct.wordLen = UART_WROD_LENGTH_8BIT;
uartInitStruct.dmaEn = UART_DMA_DISABLE;
uartInitStruct.rxTriggerLevel = 16; // 1~29
// 该UART接收FIFO的数据个数小于设置的阈值,设置触发接收超时中断的超时时间值
uartInitStruct.idle_time = UART_RX_IDLE_2BYTE; // idle interrupt wait time
uartInitStruct.TxWaterlevel = 15; // Better to equal TX_FIFO_SIZE(16)- GDMA_MSize
uartInitStruct.RxWaterlevel = 1; // Better to equal GDMA_MSize
uartInitStruct.TxDmaEn = DISABLE;
uartInitStruct.RxDmaEn = DISABLE;
UART_Init(PWM_UART, &uartInitStruct);
/* enable rx interrupt and line status interrupt 接收中断,接收总线错误中断,uart空闲中断*/
UART_INTConfig(PWM_UART, UART_INT_RD_AVA | UART_INT_LINE_STS | UART_INT_IDLE, ENABLE);
/* Enable UART IRQ */
NVIC_InitTypeDef nvic_init_struct;
nvic_init_struct.NVIC_IRQChannel = PWM_UART_IRQ;
nvic_init_struct.NVIC_IRQChannelCmd = ENABLE;
nvic_init_struct.NVIC_IRQChannelPriority = 3; // 中断优先级 : 0最高
NVIC_Init(&nvic_init_struct);
// pwm_UART1_handle 为uart1 中断处理函数
RamVectorTableUpdate(Uart1_VECTORn, pwm_UART1_handle);
2. 串口发送实现
使用串口开发板,连接RX引脚到 RTL8762C的TX引脚。就可以看到下面的打印日志。
/* Send demo string test*/
char *demoStr = "### Welcome to use RealTek Bumblebee ###\r\n";
uint8_t demoStrLen = strlen(demoStr);
memcpy(String_Buf, demoStr, demoStrLen);
uart_senddata_continuous(PWM_UART, String_Buf, demoStrLen);
/**
* @brief UARt send data continuous.
* @param No parameter.
* @return void
*/
static void uart_senddata_continuous(UART_TypeDef *UARTx, const uint8_t *pSend_Buf, uint16_t vCount) {
uint8_t count;
while (vCount / UART_TX_FIFO_SIZE > 0) {
while (UART_GetFlagState(UARTx, UART_FLAG_THR_EMPTY) == 0)
;
for (count = UART_TX_FIFO_SIZE; count > 0; count--) {
UARTx->RB_THR = *pSend_Buf++;
}
vCount -= UART_TX_FIFO_SIZE;
}
while (UART_GetFlagState(UARTx, UART_FLAG_THR_EMPTY) == 0)
;
while (vCount--) {
UARTx->RB_THR = *pSend_Buf++;
}
}
3. 中断函数处理
可以处理发送结束中断,接收中断,错误中断。
处理逻辑取决于业务实现。后续待补充。
static void pwm_UART1_handle(void) {
uint8_t rx_data;
uint32_t int_status;
uint32_t line_error;
uint8_t fifo_len;
/* read interrupt id */
int_status = UART_GetIID(UART1);
/* disable interrupt 处理中断的时候,禁用中断 */
UART_INTConfig(UART, UART_INT_RD_AVA | UART_INT_LINE_STS, DISABLE);
// 如果是收到RX 完成的中断
if (UART_GetFlagState(UART, UART_FLAG_RX_IDLE) == SET) {
UART_INTConfig(UART, UART_INT_IDLE, DISABLE);
DBG_DIRECT("UART0_FLAG_RX_IDLE: %d", pwm_uart_msg.len);
// TODO
UART_INTConfig(UART, UART_INT_IDLE, ENABLE);
}
switch (int_status) {
/* tx fifo empty */
case UART_INT_ID_TX_EMPTY:
/* do nothing 发送完成中断 */
break;
/* rx data valiable */
case UART_INT_ID_RX_LEVEL_REACH:
case UART_INT_ID_RX_TMEOUT:
fifo_len = UART_GetRxFIFOLen(UART);
for (uint8_t i = 0; i < fifo_len; ++i) {
UART_ReceiveData(UART, &rx_data, 1);
pwm_uart_msg.data[pwm_uart_msg.len] = rx_data;
pwm_uart_msg.len += 1;
if (pwm_uart_msg.len >= PWM_UART_DATA_MAX_LEN) {
// pwm_send_uart_msg(&pwm_uart_msg);
pwm_uart_msg.len = 0;
}
}
break;
/* receive line status interrupt */
case UART_INT_ID_LINE_STATUS:
line_error = UART->LSR;
// printe("data_uart_isr Line status error, fail = %d!", line_error);
break;
default:
break;
}
/* enable interrupt again */
UART_INTConfig(UART, UART_INT_RD_AVA | UART_INT_LINE_STS, ENABLE);
return;
}
4. 中断源
待使能或失能的uart中断源
5. 中断标识
/** @defgroup UART_Interrupt_Identifier UART Interrupt Identifier
* @{
*/
// UART接收总线错误中断
#define UART_INT_ID_LINE_STATUS ((uint16_t)(0x03 << 1))
// rx trigger level reached interrupt
#define UART_INT_ID_RX_LEVEL_REACH ((uint16_t)(0x02 << 1))
#define UART_INT_ID_RX_TMEOUT ((uint16_t)(0x06 << 1))
#define UART_INT_ID_TX_EMPTY ((uint16_t)(0x01 << 1))
#define UART_INT_ID_MODEM_STATUS ((uint16_t)(0x00 << 1))