cancel
Showing results for 
Search instead for 
Did you mean: 

Simple UART Tx. Using HY-mini STM32V eval. kit.

patrickbrataas9
Associate II
Posted on December 10, 2012 at 03:33

I have been trying to get UART working for the last couple of days with no luck. I have tested an UART example code and it worked. So clearly there is something I am missing. I would really appreciate any hints, tips, feedbacks etc. Here is the code:

#include ''stm32f10x.h''
int main(void)
{
//Inits.
RCC->APB2ENR |= (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN);
GPIOA->CRH |= (GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_1 | GPIO_CRH_MODE9_0);
USART1->CR2 &= (~USART_CR2_CPOL | ~USART_CR2_CPHA | ~USART_CR2_CLKEN | ~USART_CR2_LBCL | ~USART_CR2_STOP);
USART1->CR1 &= (~USART_CR1_M | ~USART_CR1_PCE | ~USART_CR1_PS | ~USART_CR1_TE | ~USART_CR1_RE);
USART1->CR1 |= USART_CR1_TE;
USART1->CR3 &= (~USART_CR3_CTSE | ~USART_CR3_RTSE);
USART1->BRR = ( (0x0034 << 
4
) | (0x0001) ); //9600 @8MHz
//USART1->BRR = ( (0x0004 << 
4
) | (0x0005) ); //115200 @8MHz
//USART1->BRR = ( (0x0027 << 
4
) | (0x0001) ); //115200 @72MHz
USART1->CR1 |= USART_CR1_UE;
while(1)
{
USART1->DR = (uint8_t) 0xAA;
while(! (USART1->CR1 & USART_SR_TC) );
//while(! (USART1->CR1 & USART_SR_TXE) );
}
}

#simple #hy-mini #stm32 #uart
9 REPLIES 9
Posted on December 10, 2012 at 04:00

Observations:

Register level programming requires a knowledge about what you're doing.

Data should be masked onto registers so as not to disturb bits you don't want to change.

ORing multiple NOT terms doesn't do what you want.

The status is in USARTx->SR not USARTx->CR1

I'd front test for TXE, back testing for TC has to be the slowest and least efficient method.

USARTx->BRR = 8000000 / 9600;  is clearer for 16x oversampling

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
patrickbrataas9
Associate II
Posted on December 10, 2012 at 16:58

Thank you for your help. I am used to register level programming on other platforms, but this is my first STM32 ARM. I really wonder myself why I was or-ing not terms anyway.. I made some masks that does the same that was intended. Changed CR1 to SR (typo). Front test for TXE even though in this code I was just trying to first output anything. The last line you wrote I don't fully understand what you are trying to tell me. I know UART receiver oversample by 16 x baud rate. After making these changes I receive data in my terminal even though it's rubbish. I get a ''UART receiver framing error'' which I would normally consider a baud rate problem or set incorret start/stop bits etc. I am starting to wonder if the PL2303HX USART-to-USB chip is doing something ''funny''. I will keep trying and post if I figure it out. And as always, all help is very very appreciated!

Updated code:

<pre>

#include ''stm32f10x.h''

#define CRH_CLEAR_MASK ((uint32_t) 0xFFFFFF0F)

#define CR1_CLEAR_MASK ((uint16_t) 0x09F3)

#define CR2_CLEAR_MASK ((uint16_t) 0xC0FF)

#define CR3_CLEAR_MASK ((uint16_t) 0x0CFF)

//Delay fucntion

void DELAY(int delay)

{

volatile int dly;

for(dly = 0; dly < delay; dly++);

}

int main(void)

{

//Inits.

RCC->APB2ENR |= (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN);

GPIOA->CRH &= CRH_CLEAR_MASK;

GPIOA->CRH |= (GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_1 | GPIO_CRH_MODE9_0);

USART1->CR2 &= CR2_CLEAR_MASK;

USART1->CR1 &= CR1_CLEAR_MASK;

USART1->CR1 |= USART_CR1_TE;

USART1->CR3 &= CR3_CLEAR_MASK;

USART1->BRR = ( (0x0034 << 4) | (0x0001) ); //9600 @8MHz

//USART1->BRR = ( (0x0004 << 4) | (0x0005) ); //115200 @8MHz

//USART1->BRR = ( (0x0027 << 4) | (0x0001) ); //115200 @72MHz

USART1->CR1 |= USART_CR1_UE;

DELAY(300000000);

while(1)

{

while(! (USART1->SR & USART_SR_TXE) );

USART1->DR = (uint32_t) 0x000000AA;

//while(! (USART1->SR & USART_SR_TC) );

}

}

</pre>

Picture from RealTerm:

http://i45.tinypic.com/w1g3e1.jpg

Posted on December 10, 2012 at 17:54

My observation with BRR is that 4-bits of fractional baud rate is conveniently aligned with 16x oversampling. So rather than playing bit shifting games one can simply divide the bus clock by the baud rate, and let the compiler compute the constant.

If the baud rates aren't working out right, consider if you are really clocking at 8 MHz. The ST CMSIS library (3.5.0) should be calling SystemInit() before heading into C startup code, and this will nominally set the clock to 72 MHz. (~1 | ~2) == 0xFFFF ~(1 | 2) == 0xFFFC Library code would look a bit like this

// STM32F1xx USART1 (USART1 TX PA.09, RX PA.10) - sourcer32@gmail.com
#include ''stm32F10x.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
/* Enable GPIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Enable UART clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA.09 USART1.TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // PA.10 USART1.RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
/* USART resources configuration (Clock, GPIO pins and USART registers) ----*/
/* USART configured as follow:
- BaudRate = 9600 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
USART_InitStructure.USART_BaudRate = 9600;
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 configuration */
USART_Init(USART1, &USART_InitStructure);
/* Enable the USART1 */
USART_Cmd(USART1, ENABLE);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
USART_Configuration();
while(1)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // Wait for Empty
USART_SendData(USART1, 0x49); // Send 'I'
}
while(1); // Don't want to exit
}

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
patrickbrataas9
Associate II
Posted on December 11, 2012 at 00:31

The thing with the baudrate was a good trick! I looked at the system_stm32f10x.h and found that I was running at 72MHz if the startup_stm32f10x_hd call the SystemInit() function. Still not working. I also tried to call the function myself in the start of main, but startup_stm32f10x_hd should have called it before it branch to main. That did not work as well. It does partly work. When I open the COM it sometimes repeat the correct value as long as I am connected. If I disconnect and connect again it might again show the correct value, but it's like 1/5 chance. Some of the other values that are shown are: 9B, 6D, 6A. This is when I try to send the value 53. It's all in HEX. 53 and 6A are dominating, 9B and 6D sporadically happens. Just to make it clear: I do not get mixed values when connected, only repititions of one of the mentioned. Observation: If we left-shift 53 we get A6. It might seem like the receiver does not recognize the start/stop bits and therefore I only sometimes get it ''locked'' on the right payload.

Any thoughts about this?

EDIT:

I added a delay before the UART transmission starts, so I have time to open terminal etc. It then 4 out of 4 tries got the correct values in terminal. It seems like there is a problem detecting start/stop of frame. Any tip on how I can debug this without going closer to hardware?

hfs99
Associate II
Posted on December 12, 2012 at 03:02

[Edit] Yikes! it doesn't seem like the PL2303 likes those characters banging on it while it is trying to initialize or (be) enumerate(d). I posted the stuff below after ''verifying'' it worked fine under JTAG control. After I disconnected the JTAG, I couldn't even get the PL2303 to re-enumerate. Still checking - will report back later.

******************* I have the same board. And I'm pre-disposed towards register-banging myself. I would say there must be some correlation, but the last guy who posted about the same board shared Clive's philosophy. Your description sounds to me like you still have a baud-rate issue. What did you set USART1->BRR to for a 72 MHz clock? (should be 7500 decimal). I know you said you already have a working example. Here is another - the LED will blink once per second if the clock rate is 8MHz.

/* absolute minimal usart example for HY-mini */
/* assumes default 8 MHz internal clock */
#include ''stm32f10x.h''
int main(void){
/* enable clocks */
RCC->APB1ENR = RCC_APB1ENR_TIM3EN;
RCC->APB2ENR = RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
/* USART1 */
USART1->BRR = 833; /* 8MHz/9600 */
USART1->CR1 = USART_CR1_UE | USART_CR1_TE;
/* TIM3 */
TIM3->PSC = 800;
TIM3->ARR = 10000; /* 1 second */
TIM3->CCR3 = 1000;
TIM3->CCMR2 = 6 << 
4
; /* ch3 PWM mode 1 */
TIM3->CCER = TIM_CCER_CC3E; /* enable ch3 */
TIM3->CR1 = TIM_CR1_CEN;
/* GPIO */
GPIOA->CRH = 0x444444a4; /* PA8 = Tx */
GPIOB->CRL = 0x4444444a; /* PB0 = LED1 */
while (1) {
while (!(USART1->SR & USART_SR_TXE));
USART1->DR = 0x55;
}
}
void SystemInit(){
return;
}

Posted on December 12, 2012 at 22:12

I have the same board. And I'm pre-disposed towards register-banging myself. I would say there must be some correlation, but the last guy who posted about the same board shared Clive's philosophy.

 

 

There are certainly times where bit banging the registers is appropriate, my general problem with it is that it requires a more complete and nuanced understanding of the reference manual, and the silicon implementation. At least to a significantly deeper level than most beginners and newbies are willing to do.

I use register level coding in assembler, and where it's appropriate. I do it from a considered perspective, not because that's how people do it on PIC's or 8051's.

I've seen people waste man-days of time trying to get to the bottom of issues that could have been easily avoided, and I'm not predisposed to raking through ill considered register level code. If people want to do this, then they need to be ready to eat their own dog food and debug it themselves.

It also makes the code a pig to support, change to different pins, timers and chips. If you want the code to have a shelf life beyond the initial development, and you don't want future developers looking to harm you, I'd really try and avoid it.

Initialization code is mostly throw away, if it's footprint becomes unacceptable there are ways to automate or table drive it which are far more efficient than screeds of code banging away on cryptically named registers and bits.

I like and recommend the library because it improves my production of working code. That I can bang out working examples in a couple of minutes while pondering more complex problems is perhaps testament to that. I have an archive of viable C code older than a lot of the forum members. Although looking at some of my fellow embedded developers in real life there seem to be a lot of 40-50 year olds, apparently all the young kids are doing .NET or Java.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
patrickbrataas9
Associate II
Posted on December 13, 2012 at 02:18

Thanks for testing this! I think this might be a PL2303 chip problem, maybe the chip is a china fake(even though i dont get the error: 10)? :p If I dont figure this out within the time im done with the eva. kit. I might replace it with a different chip when I make my own PCB. (Even though it will bug me for the rest of my life if I dont figure this out).

I understand what you are saying Clive, but I enjoy the hardware close programming and that I have to really understand how it works. I dont enjoy the abstraction as much for learning purposes, but ofcourse it has many advantages. I do abstract programming aswell, but then it's for more ''pure'' software like java, GUI, python etc.

hfs99
Associate II
Posted on December 13, 2012 at 02:29

After checking, I've tentatively concluded that the ''yikes'' behavior of the PL2303 occurs only if I disconnect the JTAG adapter with the power on. That being an illegal / out-of-bounds activity, I won't waste more bandwidth on it. On my system (x86, Linux Mint), the code I posted appears to work as expected for any number of USB disconnects and reconnects as long as JTAG disconnects are not involved.

I intended the register banging correlation comment as a joke; actually I agree with Clive 100%, or at least 99%.

What I feel: is that if I'm responsible for a design, I should be intimately familiar with every aspect of the chip and code I'm using, down to the register and assembly language level, so that when a problem occurs I know exactly how the routines I call work. From this point of view, the idea of working with register level code during a ''familiarization phase'', and then moving to something maintainable for production seems attractive.

What I see: The people who are actually making embedded systems work for a living (not me: hmm, speaking of correlations...) don't have time for nonsense like a ''familiarization phase''. They have to get something working, possibly tune the performance a bit, and get on with the next job. And yes, the ones who have lasted long have been burned by non-maintainable code enough times that they feel strongly about it.

patrickbrataas9
Associate II
Posted on December 13, 2012 at 14:07

I tested your program. It works like mine + it can be reconnected and that's no problem. I find it strange since I can not find any significant difference between our programs.. Anyway, thanks for the help! I'll just try some more and continue from here on =)