cancel
Showing results for 
Search instead for 
Did you mean: 

Why does the debugger not respond after UE bit is set for UART4?

JCorl.1
Senior

Hello everyone!

My setup uses a STM32407VG. I have been using for some time now and have gotten used to how to read the datasheet and use some of features. Today I am trying to get UART4 transmitting some data.

Here is how I went about getting it all setup:

  1. UART4 TX can be used on PC10. Therefore we must enable the AHB1 to turn on GPIOC.
  2. The UART4 module itself is one APB1 so that must be enabled as well.
  3. Via MODER, OTYPE, OSPEEDR PUPDR, I also make sure its push pull, disabled pullups and output speed is medium. Pretty sure I don’t need to do this but I did it anyway!
  4. Via AFR[1], I set the MODER register for GPIOC to be as alternate function mode.
  5. My system clock is running at 168MHz (verified from previous projects), and my APB1 PCLK1 is 42MHz. Via the BRR, I set the baudrate and used this formula: BRR = [pclk + (baud/2)] / baud. I set CR1 to 0x04 to set the TE bit and other parameters.
  6. Here is where I get some problems, I set the UE bit in CR1.

I did step through the debugger (via STLINK) and it appears I am setting all of the correct bits. But when I land on that UE bit, I get the error (in the console) Target is not responding, retrying… until it times out. Below is a code snippet.

/* UART Functions */
 
void UART4_Config()
 
{
 
	// Enable GPIO C
 
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
 
 
	// Enable the UART (PC10=TX PC11=RX)
 
	RCC->APB1ENR |= DKO_UART4_ENABLE;
 
 
	// UART4 TX PIN
 
	GPIOC->MODER &= ~(GPIO_MODER_MODE10); // Clear pin mode field
 
	GPIOC->MODER |= GPIO_MODER_MODER10_1; // Set pin mode field as alternate
 
	GPIOC->OTYPER &= ~(GPIO_OTYPER_OT10); // Clear output type field (push-pull by default)
 
	GPIOC->OSPEEDR &= ~(GPIO_OTYPER_OT10); // Clear output speed field (low by default)
 
	GPIOC->OSPEEDR |= GPIO_OSPEEDR_OSPEED10_0; // Set to medium speed
 
	GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPD10); // Clear pullup/ pulldown mode field (none as default)
 
	GPIOC->AFR[1] &= ~(1U << 8); // Set alternate function to be AF8, bit 8
 
	GPIOC->AFR[1] &= ~(1U << 9); // Set alternate function to be AF8, bit 9
 
	GPIOC->AFR[1] &= ~(1U << 10); // Set alternate function to be AF8, bit 10
 
	GPIOC->AFR[1] |= (1U << 11); // Set alternate function to be AF8, bit 11
 
 
	// UART4 SPECIFIC CONFIG
 
	UART4->BRR = 2188; // Set baudrate to be 19200; formula is BRR = [pclk + (baud/2)] / baud
 
	UART4->CR1 = (1U << 3); // Set the TE bit (transmitter enable bit)
 
	UART4->CR1 |= (1U << 13); // Set the UE bit (uart enable bit)
 
}

I never used a UART other than on things like BASIC STAMP, PICAXE, and ARDUINO. It is a little more setup with bare metal STM32F407 but it looked pretty doable. Any hints would be greatly appreciated! Thanks for your time!

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

Might not be it, but the RM says to enable UE first, then do everything else.

0693W00000FBg7VQAT.png 

Code is easier to read if you use standard defines than custom bits

UART4->CR1 |= (1U << 13); --> UART4->CR1 |= USART_CR1_UE;

Custom board? Make sure PC10 isn't connected to anything else that will disrupt the debugger. Set it as GPIO and toggle it.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

10 REPLIES 10
TDK
Guru

Might not be it, but the RM says to enable UE first, then do everything else.

0693W00000FBg7VQAT.png 

Code is easier to read if you use standard defines than custom bits

UART4->CR1 |= (1U << 13); --> UART4->CR1 |= USART_CR1_UE;

Custom board? Make sure PC10 isn't connected to anything else that will disrupt the debugger. Set it as GPIO and toggle it.

If you feel a post has answered your question, please click "Accept as Solution".
JCorl.1
Senior

Hey thanks for the reply! I properly corrected the order and also used the standard defines where it was missing.

void UART4_Config()
{
	// Enable GPIO C
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
 
	// UART4 TX PIN GPIO SETUP
	GPIOC->MODER &= ~(GPIO_MODER_MODE10);		 // Clear pin mode field
	GPIOC->MODER |= GPIO_MODER_MODER10_1;		 // Set pin mode field as alternate
	GPIOC->OTYPER &= ~(GPIO_OTYPER_OT10);	 	 // Clear output type field (push-pull by default)
	GPIOC->OSPEEDR &= ~(GPIO_OTYPER_OT10); 	 	 // Clear output speed field (low by default)
	GPIOC->OSPEEDR |= GPIO_OSPEEDR_OSPEED10_0;	 // Set to medium speed
	GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPD10);		 // Clear pullup/ pulldown mode field (none as default)
	GPIOC->AFR[1] &= ~(1U << 8);    			 // Set alternate function to be AF8, bit 8
	GPIOC->AFR[1] &= ~(1U << 9);				 // Set alternate function to be AF8, bit 9
	GPIOC->AFR[1] &= ~(1U << 10);				 // Set alternate function to be AF8, bit 10
	GPIOC->AFR[1] |= (1U << 11);				 // Set alternate function to be AF8, bit 11
 
	// STEP 0 - Enable the bus to UART4
	RCC->APB1ENR |= DKO_UART4_ENABLE;
 
	// STEP 1 - Enable the UART (PC10=TX PC11=RX) by setting the UE bit (uart enable bit)
	UART4->CR1 |= (USART_CR1_UE);
 
	// STEPS 2, 3, and (not 4) - sets the M, SOP, and TE bits
	UART4->CR1 |= (USART_CR1_TE);
 
	// STEP 6 - Set baudrate to be 19200; formula is BRR = [pclk + (baud/2)] / baud
	UART4->BRR = 2188;
}

Yes its a custom board. I checked to make sure I was able to toggle it when its configured as an output (push-pull). I got alternating signals when toggling it in a while loop. So the pin seems to be okay. I should note there is a 1kohm pullup on it for a different configuration in my project (open drain mode for 1-wire bit banging). It doesn't seem to hurt it when in strictly output mode. Since UART is configured as push-pull as well, I think its okay.

When I run the altered code, I can set the UE bit fine now. The target does not respond when it executes its last line (trying to return from the function). So I tried commenting in and out some code. I found that UART4->BRR was causing problems with the debugger. Maybe changing the baudrate messes up debugging? It seems so. So I let the code run and ran an infinite while loop..... I finally get data! But garbage data. I am using my protocol analyzer within the logic analyzer I am using and it keeps getting "framing error". Hey I am closer 🙂

JCorl.1
Senior

Hmmmm yeah there must be something weird going on. Okay so call me crazy but I hear clicking in the MCU. You know when like power MOSFETs are shorting and constantly are turning on and off due to some weird error condition? I hear something similar. It stop when comment out the uart config function I made. Going to poke around some more to see what else I find out.

TDK
Guru

You're still not doing the correct order of initialization. TE should be last.

I would test the code on known good hardware such as a nucleo board. Upload your schematic if you want.

If you feel a post has answered your question, please click "Accept as Solution".
JCorl.1
Senior

Sorry about that! I was careless with the pasting of the up to date code. Here it is:

void UART4_Config()
{
	// Enable GPIO C
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
 
	// UART4 TX PIN GPIO SETUP
	GPIOC->MODER &= ~(GPIO_MODER_MODE10);		 // Clear pin mode field
	GPIOC->MODER |= GPIO_MODER_MODER10_1;		 // Set pin mode field as alternate
	GPIOC->OTYPER &= ~(GPIO_OTYPER_OT10);	 	 // Clear output type field (push-pull by default)
	GPIOC->OSPEEDR &= ~(GPIO_OTYPER_OT10); 	 	 // Clear output speed field (low by default)
	GPIOC->OSPEEDR |= GPIO_OSPEEDR_OSPEED10_0;	 // Set to medium speed
	GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPD10);		 // Clear pullup/ pulldown mode field (none as default)
	GPIOC->AFR[1] &= ~(1U << 8);    			 // Set alternate function to be AF8, bit 8
	GPIOC->AFR[1] &= ~(1U << 9);				 // Set alternate function to be AF8, bit 9
	GPIOC->AFR[1] &= ~(1U << 10);				 // Set alternate function to be AF8, bit 10
	GPIOC->AFR[1] |= (1U << 11);				 // Set alternate function to be AF8, bit 11
 
	// STEP 0 - Enable the bus to UART4
	RCC->APB1ENR |= DKO_UART4_ENABLE;
 
	// STEP 1 - Enable the UART (PC10=TX PC11=RX) by setting the UE bit (uart enable bit)
	UART4->CR1 |= (USART_CR1_UE);
 
	// STEP 2 - Set the M bit
	UART4->CR1 |= (USART_CR1_M);
 
	// STEP 3 - Set the stop bits
	UART4->CR1 |= (USART_CR2_STOP_1);
 
	// STEP 4
	// NONE
 
	// STEP 5 - Set baudrate to be 19200; formula is BRR = [pclk + (baud/2)] / baud
	UART4->BRR = 4376;//2188;
 
	// STEP 6 - Set the TE bit
	UART4->CR1 |= USART_CR1_TE;
}

I think the 1kohm pullups really messed up the UART. Took some hot air and removed them, did the trick. Now I am finally getting some clear data. Thank you for the help! Where can I place some money to buy you a coffee? :p

If the purpose of using register level coding is to be efficient, you might consider folding the multiple LOAD/STORE (RMW) operations to achieve that end.

The Compiler can also pre-compute constants, so math doesn't become part of the code, improving clarity, and eases porting/changes.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Oh interesting. I will read up on this. The register level coding is honestly more for education. Though I have been using it more and more for my own projects. I dunno I find it easier to understand a bottom up approach when learning. Starting with the HAL, I felt disconnected.

Glad you got it solved. However, I can't see why a 1kOhm pullup should be causing any issues here. It's almost as if the power supply is insufficient, which causes a power rail to drop and the debugger to lose contact when it tries to drive PC10 low. Removing the pullup would reduce the load and mitigate the issue. But PC10 can drive 3.3mA no problem under normal scenarios.

The SET_BIT, CLEAR_BIT, and less so the MODIFY_REG macros are useful to avoid typos and improve readability. I find a missing "~" hard to spot as my eyes gloss over simple statements. I may be in the minority here in preferring them.

#define SET_BIT(REG, BIT)     ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT)   ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT)    ((REG) & (BIT))
#define CLEAR_REG(REG)        ((REG) = (0x0))
#define WRITE_REG(REG, VAL)   ((REG) = (VAL))
#define READ_REG(REG)         ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

> Where can I place some money to buy you a coffee?

No need, but thank you for the offer. Pay it forward.

If you feel a post has answered your question, please click "Accept as Solution".
JCorl.1
Senior

I actually didn't know about these. Are they portable?

Yes I am not sure why the pullups were causing the issue. I have nothing else connected to that tx line. I will look into it more as I play around.

Thanks again for the help! I am already paying it forward by helping someone understand ADC circuits and opamps tomorrow over a Discord call so rest assured the good deed will be paid back 🙂