2020-09-16 06:12 AM
Dear community,
I plan to use the USART2 of my STM32F407VE board for an IrDA communication (8N1, 115200 Baud @ 8 MHz fPCLK). I started with initializing my USART2 periphery on the register level (I don't use STM32CubeIDE). This seems to work fine. However, I have several issues that I try to distinguish by the following numbers:
1.First issue is that when I try to write to the data register DR for transmission, my debugger tells me that no value is written to it:
if ((write_data_ptr != transmit_data_ptr) && ((USART2->SR & (1 << USART_SR_TXE_Pos)) == USART_SR_TXE))
{
USART2->CR1 |= (1 << USART_CR1_TE_Pos); // send an idle frame
USART2->DR = tx_buffer[transmit_data_ptr];
transmit_data_ptr = (transmit_data_ptr + 1) & (BUFFER_SIZE - 1);
while((USART2->SR & USART_SR_TC_Msk) == USART_SR_TC) {}; // wait for transmission to finish
toggle_LED(LED_D3);
}
First I thought it is due to the fact that the DR register actually consists of two registers on the hardware - one for transmission and one for receiving. I thought that my debugging software/my debugger can't distinguish between those two because it shows only one register anyway. But I would expect at least that the TXE flag (transmit data register empty) in the status register SR is reset, because I just wrote something to the register. However this doesn't happen. But why?
2.When I debug the above code, row number 67 is executed and does what I expect (incrementing the pointer that indicates which data is already transmitted). After that, I planned to wait for the transmission to be complete. If I resume the program after row 67, the code waits but immediately jumps back to row 67, instead of holding at line 69 (which I purposelly inserted for this problem). After this happened, the code gets completely stuck at line 68 and waiting forever, despite that the status register of USART2 did not change.
3.My interrupt for the USART2 never gets called. I am not sure if that is the case because I used the wrong name (because I did something similar for a timer interrupt in another question I asked recently in this forum). I use the interrupt
void USART2_IRQHandler(void) {
// do something
}
And just as in my previously asked question, it doesn't get called even though the compiler does not return an error or warning. Where can I generally look up what those interrupt vectors are called? Just for completion, here is my init code for the USART2:
void initIrda(void)
{
if (!isIrdaInitialized())
{
write_data_ptr = 0;
transmit_data_ptr = 0;
received_data_ptr = 0;
read_data_ptr = 0;
GPIOA->AFR[0] |= (0b0111 << GPIO_AFRL_AFSEL2_Pos); // Alternate function AF7 for PA2 and PA3
GPIOA->AFR[0] |= (0b0111 << GPIO_AFRL_AFSEL3_Pos);
startIrda();
USART2->CR1 |= (1 << USART_CR1_TXEIE_Pos) // Enable TX-Interrupts
| (1 << USART_CR1_TCIE_Pos) // Enable Transmission Complete Interrupts
| (1 << USART_CR1_PEIE_Pos) // Enable Interrupts for parity errors
| (1 << USART_CR1_IDLEIE_Pos) // Enable Interrupt when idle line is detected
| (1 << USART_CR1_RXNEIE_Pos) // Enable RX-Interrupts
| (1 << USART_CR1_TE_Pos) // Enable Transmitter
| (1 << USART_CR1_RE_Pos); // Enable Receiver
USART2->CR1 |= (1 << USART_CR1_UE_Pos); // enable UART
USART2->CR1 &= ~(1 << USART_CR1_M_Pos); // 1 Start bit, 8 Data bits, n Stop bit
USART2->CR2 &= ~(0b11 << USART_CR2_STOP_Pos); // 1 Stop bit
USART2->BRR = 0x045; // Baudrate 115200 (see documentation how this value was calculated)
irda_status.initialized = 1;
}
}
void startIrda(void)
{
RCC->APB1ENR |= (1 << RCC_APB1ENR_USART2EN_Pos); // turn clock on for usart2 periphery
irda_status.running = 1;
}
Thank you in advance!
2020-09-16 06:24 AM
>>First issue is that when I try to write to the data register DR for transmission, my debugger tells me that no value is written to it:
You can't inspect it in the debugger, the DR read looks into a different register than the DR write went too.
Viewing the USART registers in the debugger is invasive. Reading DR changes what's in SR, for example.
2020-09-16 09:27 AM
You have to enable the interrupt in NVIC.
2020-09-16 09:28 AM
Also your loop waits until the transmission is not complete. You want the opposite.
2020-09-16 10:26 PM
Yeah, that makes sense. The controller can't distinguish between a read from the debugger and a read from the software. Is there any way I can test my code, like a simulator tool for the STM32 series? I know that Atmel integrates simulators in their IDE.
2020-09-17 12:50 AM
But: I still would expect that after my code writes something to the data register, that the TXE (transmit register empty) flag in the status register should be reset. Instead, it stays at 1.