接上篇有了uart設(shè)備對(duì)象及rt_uart_ops結(jié)構(gòu)體以后,我們就需要提供對(duì)應(yīng)的真實(shí)的能操控硬件的函數(shù),其實(shí)真正操作的硬件的函數(shù)并不多,創(chuàng)建的結(jié)構(gòu)體對(duì)象如下:
static const struct rt_uart_ops stm32_uart_ops =
{
.configure = stm32_configure,
.control = stm32_control,
.putc = stm32_putc,
.getc = stm32_getc,
.dma_transmit = stm32_dma_transmit
};
先來看下基于hal庫代碼實(shí)現(xiàn)的stm32_configure的完整代碼,當(dāng)你需要更換其它單片機(jī)時(shí),再系統(tǒng)沒有提供對(duì)應(yīng)的bsp的情況下,你可以仿照代碼進(jìn)行重構(gòu)該函數(shù)用于適用于特殊的硬件,系統(tǒng)也提供了很多種不同的芯片的bsp:
static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
struct stm32_uart *uart;
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
uart = rt_container_of(serial, struct stm32_uart, serial);
uart->handle.Instance = uart->config->Instance;
uart->handle.Init.BaudRate = cfg->baud_rate;
uart->handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
uart->handle.Init.Mode = UART_MODE_TX_RX;
uart->handle.Init.OverSampling = UART_OVERSAMPLING_16;
switch (cfg->data_bits)
{
case DATA_BITS_8:
uart->handle.Init.WordLength = UART_WORDLENGTH_8B;
break;
case DATA_BITS_9:
uart->handle.Init.WordLength = UART_WORDLENGTH_9B;
break;
default:
uart->handle.Init.WordLength = UART_WORDLENGTH_8B;
break;
}
switch (cfg->stop_bits)
{
case STOP_BITS_1:
uart->handle.Init.StopBits = UART_STOPBITS_1;
break;
case STOP_BITS_2:
uart->handle.Init.StopBits = UART_STOPBITS_2;
break;
default:
uart->handle.Init.StopBits = UART_STOPBITS_1;
break;
}
switch (cfg->parity)
{
case PARITY_NONE:
uart->handle.Init.Parity = UART_PARITY_NONE;
break;
case PARITY_ODD:
uart->handle.Init.Parity = UART_PARITY_ODD;
break;
case PARITY_EVEN:
uart->handle.Init.Parity = UART_PARITY_EVEN;
break;
default:
uart->handle.Init.Parity = UART_PARITY_NONE;
break;
}
#ifdef RT_SERIAL_USING_DMA
uart->dma_rx.last_index = 0;
#endif
if (HAL_UART_Init(&uart->handle) != HAL_OK)
{
return -RT_ERROR;
}
return RT_EOK;
}
代碼很長(zhǎng),但是功能很簡(jiǎn)單就是對(duì)串口進(jìn)行初始化,設(shè)置串口波特率,硬件流控,串口模式、串口采樣、數(shù)據(jù)位、停止位、DMA相關(guān)參數(shù)、最后調(diào)用HAL_UART_Init()完成串口的初始化功能。
接下來看下stm32_control函數(shù)的代碼,代碼雖長(zhǎng)單功能并不復(fù)雜:
static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct stm32_uart *uart;
#ifdef RT_SERIAL_USING_DMA
rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
#endif
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct stm32_uart, serial);
switch (cmd)
{
/* disable interrupt */
case RT_DEVICE_CTRL_CLR_INT:
/* disable rx irq */
NVIC_DisableIRQ(uart->config->irq_type);
/* disable interrupt */
__HAL_UART_DISABLE_IT(&(uart->handle), UART_IT_RXNE);
#ifdef RT_SERIAL_USING_DMA
/* disable DMA */
if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX)
{
HAL_NVIC_DisableIRQ(uart->config->dma_rx->dma_irq);
if (HAL_DMA_Abort(&(uart->dma_rx.handle)) != HAL_OK)
{
RT_ASSERT(0);
}
if (HAL_DMA_DeInit(&(uart->dma_rx.handle)) != HAL_OK)
{
RT_ASSERT(0);
}
}
else if(ctrl_arg == RT_DEVICE_FLAG_DMA_TX)
{
HAL_NVIC_DisableIRQ(uart->config->dma_tx->dma_irq);
if (HAL_DMA_DeInit(&(uart->dma_tx.handle)) != HAL_OK)
{
RT_ASSERT(0);
}
}
#endif
break;
/* enable interrupt */
case RT_DEVICE_CTRL_SET_INT:
/* enable rx irq */
HAL_NVIC_SetPriority(uart->config->irq_type, 1, 0);
HAL_NVIC_EnableIRQ(uart->config->irq_type);
/* enable interrupt */
__HAL_UART_ENABLE_IT(&(uart->handle), UART_IT_RXNE);
break;
#ifdef RT_SERIAL_USING_DMA
case RT_DEVICE_CTRL_CONFIG:
stm32_dma_config(serial, ctrl_arg);
break;
#endif
case RT_DEVICE_CTRL_CLOSE:
if (HAL_UART_DeInit(&(uart->handle)) != HAL_OK )
{
RT_ASSERT(0)
}
break;
}
return RT_EOK;
}
主要看一下幾個(gè)控制參數(shù):RT_DEVICE_CTRL_CLR_INT關(guān)閉中斷,如果有使用dma則關(guān)閉DMA。RT_DEVICE_CTRL_SET_INT:開啟終端,如果有使用dma則采用dma_config功能打開dma。RT_DEVICE_CTRL_CLOSE:關(guān)閉串口,就這幾個(gè)功能。
發(fā)送函數(shù)功能最簡(jiǎn)單,輕松TC中斷標(biāo)記,將數(shù)據(jù)放入DR數(shù)據(jù)寄存器中,while循環(huán)等待TC中斷觸發(fā)(DR數(shù)據(jù)寄存器為空):
static int stm32_putc(struct rt_serial_device *serial, char c)
{
struct stm32_uart *uart;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct stm32_uart, serial);
UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TC);
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
|| defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) \
|| defined(SOC_SERIES_STM32G4)
uart->handle.Instance->TDR = c;
#else
uart->handle.Instance->DR = c;
#endif
while (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) == RESET);
return 1;
}
接下來是讀取數(shù)據(jù),這里有個(gè)有意思的現(xiàn)象,看過源碼你會(huì)發(fā)現(xiàn)讀取數(shù)據(jù)和寫入數(shù)據(jù)訪問的實(shí)際的硬件寄存器都是一樣的,DR or RDR,那么你會(huì)不會(huì)有個(gè)疑問,那么某一刻讀取的數(shù)據(jù)會(huì)不會(huì)是剛寫入的數(shù)據(jù),代碼之后揭曉:
static int stm32_getc(struct rt_serial_device *serial)
{
int ch;
struct stm32_uart *uart;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct stm32_uart, serial);
ch = -1;
if (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_RXNE) != RESET)
{
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
|| defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) \
|| defined(SOC_SERIES_STM32G4)
ch = uart->handle.Instance->RDR & 0xff;
#else
ch = uart->handle.Instance->DR & 0xff;
#endif
}
return ch;
}
揭曉答案啦:這里以DR為例,其實(shí)它是一對(duì)神奇的雙胞胎,一個(gè)名字對(duì)應(yīng)著兩個(gè)真實(shí)的寄存器,當(dāng)你寫入數(shù)據(jù)時(shí)實(shí)際寫入的是發(fā)送DR,當(dāng)你讀取數(shù)據(jù)時(shí)實(shí)際訪問的是接收DR,是通過你對(duì)硬件的讀or寫操作,硬件自行對(duì)應(yīng)的,當(dāng)年在這個(gè)問題上耗死了好些的腦細(xì)胞,也不知道是哪個(gè)天才設(shè)計(jì)的機(jī)制。
最后到了還有連續(xù)傳送字節(jié)(發(fā)送)的實(shí)現(xiàn),借助的硬件的DMA技術(shù)實(shí)現(xiàn)的:
static rt_size_t stm32_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
{
struct stm32_uart *uart;
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(buf != RT_NULL);
uart = rt_container_of(serial, struct stm32_uart, serial);
if (size == 0)
{
return 0;
}
if (RT_SERIAL_DMA_TX == direction)
{
if (HAL_UART_Transmit_DMA(&uart->handle, buf, size) == HAL_OK)
{
return size;
}
else
{
return 0;
}
}
return 0;
}
帶著問題結(jié)束本篇吧,發(fā)送很簡(jiǎn)單 一個(gè)接一個(gè)的發(fā)送出去,那么接收呢,DR中有沒有數(shù)據(jù),是不是需要頻繁的觸發(fā)讀取函數(shù),或者讀不及時(shí)會(huì)不會(huì)被下一個(gè)來的數(shù)據(jù)將DR中的數(shù)據(jù)覆蓋,或者數(shù)據(jù)直接被丟掉呢?