STM32F429I-DISCOとUARTとDMA
UARTを使ってみる。
開発環境はいつものCooCoxのやつ。
に割り当てて、動作を確認。 せっかくなのでDMA使ってみる。 以下ソースなど。
/* とりあえずRX用のバッファを作る。(ポインタの方が良さげだけど) */ typedef struct { char rx_buffer[UART5_RX_BUFF_MAX]; // RX buffer uint16_t w_posi; // uint16_t r_posi; // uint16_t len; }UART_RX_t; static UART_RX_t sUart5_RX_buff; /* TX用のバッファ。DMAと関連付ける */ static char sUart5_TX_buff[UART5_TX_BUFF_MAX]; static DMA_InitTypeDef DMA_InitStructUART5TX; /*! ******************************************************************* * @note stream7は使えたけど、 1, 4, 5はダメだった・・・。 正確な理由を知りたいなぁ・・・。 **********************************************************************/ void Uart5_TX_DMA(char* data, uint16_t len) { if ( len < UART5_TX_BUFF_MAX ) { memcpy(sUart5_TX_buff, data, len); DMA_InitStructUART5TX.DMA_BufferSize = len; DMA_Init(DMA1_Stream7, &DMA_InitStructUART5TX); DMA_Cmd(DMA1_Stream7, ENABLE); } } /*! ******************************************************************* * **********************************************************************/ UART_RX_t* Uart5_GetRxData(void) { return (&sUart5_RX_buff); } /*! ******************************************************************* * **********************************************************************/ void UartInit(void) { sUart5_RX_buff.r_posi = 0; sUart5_RX_buff.w_posi = 0; sUart5_RX_buff.len = 0; uart_clock_init(); uart_gpio_init(); uart_peri_init(); uart_dma_init(); UartNvicInit(); // すぐに使わない場合はこいつは後回しでOK } /*! ******************************************************************* * クロック関係初期化 ※DMA使いたいので、それもまとめて記載 **********************************************************************/ static void uart_clock_init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); } /*! ******************************************************************* * GPIO 初期化 **********************************************************************/ static void uart_gpio_init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* TX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); /* Connect USART pins to AF */ GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5); /* RX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5); } /*! ******************************************************************* * ペリフェラルの初期化 **********************************************************************/ static void uart_peri_init(void) { /* - BaudRate = 115200 baud - Word Length = 8 Bits - One Stop Bit - No parity - Hardware flow control disabled (RTS and CTS signals) - Receive and transmit enabled */ USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(UART5, &USART_InitStructure); USART_Cmd(UART5, ENABLE); /* RX-Interrupt enable */ USART_ITConfig(UART5, USART_IT_RXNE, ENABLE); } /*! ******************************************************************* * DMAの初期化。 RXは固定電文長で使わない予定なので、DMA使わない **********************************************************************/ static void uart_dma_init(void) { DMA_InitStructUART5TX.DMA_Channel = DMA_Channel_4; DMA_InitStructUART5TX.DMA_PeripheralBaseAddr = (uint32_t)&UART5->DR; DMA_InitStructUART5TX.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructUART5TX.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructUART5TX.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructUART5TX.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // DMA_InitStructUART5TX.DMA_Mode = DMA_Mode_Circular; // ずーとTXループさせたいならこっち DMA_InitStructUART5TX.DMA_Mode = DMA_Mode_Normal; DMA_InitStructUART5TX.DMA_Priority = DMA_Priority_High; DMA_InitStructUART5TX.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructUART5TX.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructUART5TX.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructUART5TX.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; /*********************************************************************************** * for TX ***********************************************************************************/ DMA_DeInit(DMA1_Stream7); DMA_InitStructUART5TX.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Transmit DMA_InitStructUART5TX.DMA_Memory0BaseAddr = (uint32_t)sUart5_TX_buff; DMA_InitStructUART5TX.DMA_BufferSize = 0; DMA_Init(DMA1_Stream7, &DMA_InitStructUART5TX); /* Enable the USART Tx DMA request */ USART_DMACmd(UART5, USART_DMAReq_Tx, ENABLE); /* Enable DMA Stream Half Transfer and Transfer Complete interrupt */ DMA_ITConfig(DMA1_Stream7, DMA_IT_TC | DMA_IT_HT , ENABLE); /* Enable the DMA TX Stream */ DMA_Cmd(DMA1_Stream7, DISABLE); } /*! ******************************************************************* * 割り込み設定 **********************************************************************/ void UartNvicInit(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Configure the Priority Group to 2 bits */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /****************************************************************************** * for TX ******************************************************************************/ NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* enable UART Interrupt-Vector */ NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); sUart5_RX_buff.r_posi = 0; sUart5_RX_buff.w_posi = 0; sUart5_RX_buff.len = 0; } /*! ******************************************************************* * 割り込み解除 **********************************************************************/ void UartNvicDeInit(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Configure the Priority Group to 2 bits */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /****************************************************************************** * for TX ******************************************************************************/ NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; NVIC_Init(&NVIC_InitStructure); /* enable UART Interrupt-Vector */ NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; NVIC_Init(&NVIC_InitStructure); } /*! ******************************************************************* * @note TX DMA **********************************************************************/ void DMA1_Stream7_IRQHandler(void) { /* Test on DMA Stream Transfer Complete interrupt */ if (DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7)) { /* Clear DMA Stream Transfer Complete interrupt pending bit */ DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7); DMA_Cmd(DMA1_Stream7, DISABLE); } /* Test on DMA Stream Half Transfer interrupt */ if (DMA_GetITStatus(DMA1_Stream7, DMA_IT_HTIF7)) { /* Clear DMA Stream Half Transfer interrupt pending bit */ DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_HTIF7); } } /*! ******************************************************************* * @note RX UART IRQ **********************************************************************/ void UART5_IRQHandler(void) { if (USART_GetITStatus(UART5, USART_IT_RXNE) == SET) { sUart5_RX_buff.rx_buffer[sUart5_RX_buff.w_posi] = USART_ReceiveData(UART5); sUart5_RX_buff.w_posi++; if ( sUart5_RX_buff.w_posi == UART5_RX_BUFF_MAX ) { sUart5_RX_buff.w_posi = 0; } sUart5_RX_buff.len++; } }
感想:受信もテスト的にDMA試したけどうまくいかんかった。
ペリフェラルに対応したDMAのチャンネルとストリームがあるみたいだけど、
ネット上で正確な情報を見つけきらんかった。
とりあえずemWin使って、RX内容をMULTIEDITに表示させてみたりしたけど、
何かハイテクだった。
オーバーフローしないようにいちいちMULTIEDIT_GetTextSize()して
MULTIEDIT_SetCursorOffset()して
MULTIEDIT_GetText()して
MULTIEDIT_AddKey()でGUI_KEY_DELETEでデリートするのが面倒だったけど、
自分で作るよりemWinとか使った方がかなり簡単で良いものができると思った。
簡単なUARTの動作確認としては使えそう。