logina
logina

Reputation: 247

How do I enable UART4 STM32F215?

I am running standard CMSIS as released by ST with libc included and all the jazz. Here is the code that isn't working.

void __attribute__ ((constructor)) uart4_init() {
  // Enable the clock for uart4
  RCC->APB1ENR |= 1 << 19;
  // Enable the clock for GPIO_C, which needs to be configured to pass-through UART4
  RCC->AHB1ENR |= 1 << 2;

  // Set up the GPIOC 11 and 10 pins for UART use
  // Set to alternate function mode
  GPIOC->MODER &= ~(0b1111 << 20);
  GPIOC->MODER |= 0b1010 << 20;
  // Finally set Alternate Function to UART4, to pass through the UART
  GPIOC->AFR[1] &= ~(0b11111111 << 8);
  GPIOC->AFR[1] |= 0b10001000 << 8;

  // Set up the UART port for reasonable sending settings
  // Here follows explanations on all bits set to 1:
    // Enable the serial port
    // Set to nine bits, so we have one to spare for parity
    // (Leave default wakeup method, since unused?)
    // Enable parity
    // Enable odd parity (better at detecting speed mismatch)
    // (Do not set parity error interrupt on)
    // (Do not set transfer buffer empty interrupt on)
    // (Do not set transmission complete, since that is DMA specific)
    // (Do not set recieve buffer not empty interrupt on)
    // (Do not set idle interrupt since we don't use it)
    // (Do not enable transmitter until setup is fully done)
    // (Do not enable reciever until setup is fully done)
    // (Do not enable mute-mode, we don't use it)
    // (Do not send a break character)
  UART4->CR1 = 0b11011000000000; // Set everything up
  // The confusing part, setting the baud rate, is in separate function
  uart4_set_baud(b9600);
  // Enable sending and receiving
  UART4->CR1 |= 0b1100;
}

I have verified that RCC_APB1ENR bit 19 is set, but the control registers of UART4 don't seem to have any clock and thus don't take the assignments.

(gdb) print/x *0x40023840
$23 = 0x80000

After reading working code (HAL code, so practically obfuscated) and documentation I still cannot figure this out.

Edit: Cleaned up the code following old_timers advice. Should be a usable example now.

Edit2: Removed the interrupts to make more generally usable as base example. Especially since those interrupt bits also net you to enable the UART interrupts through NVIC.

Upvotes: 0

Views: 361

Answers (2)

0___________
0___________

Reputation: 68089

  1. When you use CMSIS use also the the human readable defines.

    RCC->APB1ENR |= 1 << 19; 
    

It is very easy to make a mistake in the number and very quickly you will forget what this line does.

 RCC->APB1ENR |= RCC_APB1ENR_UART4EN;

Shows exacltly what what it does.

You have much better examples here like:

 UART4->CR1 = 0b11011110100000;

or

 UART4->CR1 |= 0b1100;

I think that

 UART4 -> CR1 |= USART_CR1_RE | USART_CR1_TE; 

Is much easier to read and much much more error safe.

  1. After enabling the clock you need to provide the delay or read-back.

I do not use HAL - but I really like low level HAL macros for example

 __HAL_RCC_UART4_CLK_ENABLE(); 

Which correct enable the clock (remember that many STM32 have bugs in the RCC domain and require special procedure which is described in errata pages)

#define __HAL_RCC_UART4_CLK_ENABLE()  do { \
                                      __IO uint32_t tmpreg = 0x00U; \
                                      SET_BIT(RCC->APB1ENR, RCC_APB1ENR_UART4EN);\
                                      /* Delay after an RCC peripheral clock enabling */ \
                                      tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_UART4EN);\
                                      UNUSED(tmpreg); \
                                      } while(0U)

This macro is same effective as simple register assignment + readback but does it correctly and its name describes what it does.

Upvotes: 2

logina
logina

Reputation: 247

After some guided disassembling (Thanks old_timer!) I have now concluded that I am reading from the wrong addresses in my debugging, so the things I thought weren't working were working all along.

Is essence I read from 0x40024c00 when UART4 is at 0x40004c00...

After checking correcting that I find that CR1 does take the value of 0x37a0 that I have written in binary (and becomes 0x37ac when enabled) and that BRR takes the expected value of 1666 (which should be 9600 baud, if I understood the documentation right...).

After that I can check the status register after sending a test byte to the card and conclude that I have received data and validate that to check that my baud is close enough, so it is working now (enough for continued testing).

Upvotes: 0

Related Questions