2024-11-13 07:23 PM - edited 2024-11-13 07:26 PM
Hello. The USART1 TX works fine when I manually put bytes into the TDR register, but it doesn't work when I try to use DMA in printf function. Below is my initialization and transmitting code (other functions are not shown because they are related to receiving or manual transmitting):
The Transmission Complete interrupt of DMA is never triggered (so next printf call is always waiting for the first one to end), and no message is received by my putty terminal either, while manually sending message works fine.
I've checked my macros for many times according to the programming manual, and I sat here the whole day dealing with it. I worry that it might be damaged because yesterday I put it into the fridge for 5 sec to test the sensor.
Please help :(. I used direct register access to configure DMA because I liked to test my understanding.
#include "stm32l4xx_hal.h"
#include <sys/stat.h>
#define my_BAUDRATE 115200
#define USART_INSTANCE USART1
// GPIO pins
#define my_UART_PC_GPIO_TX_PORT GPIOA
#define my_UART_PC_GPIO_TX_Pin GPIO_PIN_9
#define my_UART_PC_GPIO_RX_PORT GPIOA
#define my_UART_PC_GPIO_RX_Pin GPIO_PIN_10
#define my_UART_PC_GPIO_CLKEN_CMD __HAL_RCC_GPIOA_CLK_ENABLE
// clock enable
#define my_UART_PC_CLKEN_CMD __HAL_RCC_USART1_CLK_ENABLE
// interrupts
#define my_UART_PC_IRQ USART1_IRQn
#define my_UART_PC_IRQ_HANDLER USART1_IRQHandler
#define my_UART_PC_IRQ_PRIORITY 1, 1
// DMA
#define my_DMA_TX DMA1
#define my_DMA_RX DMA1
#define my_DMA_TX_CH DMA1_Channel4
#define my_DMA_RX_CH DMA1_Channel5
#define my_DMA_TX_CHn 4
#define my_DMA_RX_CHn 5
#define my_DMA_TX_IRQn DMA1_Channel4_IRQn
#define my_DMA_TX_IRQHandler DMA1_Channel4_IRQHandler
static void my_NVIC_config();
static void my_clock_config();
static void my_GPIO_config();
static void my_UART_config();
static UART_HandleTypeDef my_UART_handle;
static DMA_HandleTypeDef my_DMA_handle;
uint8_t my_last_recv_byte;
volatile int DMA_TX_busy = 0;
char DMAbuffer[255];
void my_UART_PC_init(){
my_NVIC_config();
my_clock_config();
my_GPIO_config();
my_UART_config();
}
static void my_NVIC_config(){
HAL_NVIC_SetPriority(my_UART_PC_IRQ, my_UART_PC_IRQ_PRIORITY);
HAL_NVIC_EnableIRQ(my_UART_PC_IRQ);
}
static void my_clock_config(){
my_UART_PC_GPIO_CLKEN_CMD();
my_UART_PC_CLKEN_CMD();
__HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_PCLK2);
}
static void my_GPIO_config(){
GPIO_InitTypeDef GPIO_InitStructure;
// Configure TX pin
GPIO_InitStructure.Pin = my_UART_PC_GPIO_TX_Pin;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(my_UART_PC_GPIO_TX_PORT, &GPIO_InitStructure);
// Configure RX pin
GPIO_InitStructure.Pin = my_UART_PC_GPIO_RX_Pin;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; // Should be AF for RX
GPIO_InitStructure.Pull = GPIO_NOPULL; // Set the appropriate pull-up/pull-down
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; // Speed
GPIO_InitStructure.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(my_UART_PC_GPIO_RX_PORT, &GPIO_InitStructure);
}
static void my_UART_config(){
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
my_UART_handle.Instance = USART_INSTANCE;
my_UART_handle.Init.BaudRate = my_BAUDRATE;
my_UART_handle.Init.WordLength = UART_WORDLENGTH_8B;
my_UART_handle.Init.StopBits = UART_STOPBITS_1;
my_UART_handle.Init.Parity = UART_PARITY_NONE;
my_UART_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
my_UART_handle.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&my_UART_handle);
// DMA for TX
my_DMA_TX_CH->CCR &= !DMA_CCR_EN;
USART_INSTANCE->CR3 |= USART_CR3_DMAT; // enable USART DMA
my_DMA_TX_CH->CPAR = (uint32_t) &USART_INSTANCE->TDR; // target address
my_DMA_TX_CH->CMAR = (uint32_t) DMAbuffer;
my_DMA_TX_CH->CCR |= DMA_CCR_MINC | DMA_CCR_DIR| DMA_CCR_TCIE; // memory increment, direction, TXC IRQ
HAL_NVIC_EnableIRQ(my_DMA_TX_IRQn); // enable DMA TX interrupt
__HAL_UART_ENABLE_IT(&my_UART_handle, UART_IT_RXNE);
//__HAL_UART_ENABLE_IT(&my_UART_handle, UART_IT_TXE);
}
int _write(int file, char *ptr, int len) {
for (int i = 0; i < len; i++) {
my_UART_PC_sendByte((uint8_t)ptr[i]);
}
return len; // Return the number of characters written
/*
while(DMA_TX_busy);
for(int i=0;i<len;i++){
DMAbuffer[i] = ptr[i];
}
my_DMA_TX_CH->CNDTR=len;
my_DMA_TX_CH->CMAR = (uint32_t) DMAbuffer;
my_DMA_TX_CH->CCR |= DMA_CCR_EN;
DMA_TX_busy = 1;
return len;
*/
}
void my_DMA_TX_IRQHandler(void) {
// Check for the transfer complete interrupt
if (my_DMA_TX->ISR & DMA_ISR_TCIF4) {
my_DMA_TX->IFCR = DMA_IFCR_CTCIF4; // Clear transfer complete flag
my_DMA_TX_CH->CCR &= ~DMA_CCR_EN; // Disable DMA channel to stop TX
DMA_TX_busy = 0;
}
}