We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Gentlemen(Ladies):
I've been wrestling with trying to get output from one of the two UARTs on my Keil MCBSTR9 board (vers 3). All to no avail. I've checked baudrates and the setup of the UART and the System Control Unit. Part of the attached code works (LCD output, LED output) so I know that at least the processor is coming out of reset and is running some code. Trouble is, when I try to send a character out the port, the code hangs. If I comment out the two calls to sendchar(), the remaining code runs fine.
I've posted my code below (with comments explaining what I was attempting to do. If it is simple enough to identify what I'm doing wrong, I would greatly appreciate being educated.
Or, if deciphering my bad code is beyond the wit/patience of man, then I would appreciate a sample of any serial port code that DOES run on the MCBSTR9 board.
I apologize in advance for the appearance of the code after I copied it from the IDE to the form posting editor. I tried my best to clean it up, but I'm not at all happy with how it renders (at least on my browser). Any suggestions on how to fix that problem would be duly noted and taken on board.
//*************************** TEST.C ************************************ // Auth: R. McCoy // Date: 9/30/2006 // Gist: Blinks LEDS on port 7 of Keil MCBSTR9 board. Also TRYING to spit a // character ('A') out of COM1 (UART0). // Note: It appears that there is an error in the documentation on page 78 of // ST Manual UM0216 (STR91x Reference manual). The SCU_GPOINn register // documentation makes no sense whatsoever. Only 8 bits are shown...not // the 16 bits that should be depicted. Also, why does the table jump from // pin3 to pin7 (going right to left)? // Stat: No luck so far. // // Targ: Using the Keil MCBSTR9 Demo Board: // COM1 is connected to pins P3.0 (Rx) and P3.1 (TX) // COM2 is connected to pins P3.2 (Rx) and P3.3 (TX) // // Per Table 4 of the Str91xF (ARM966E-S) datasheet (STR912FW44.pdf): // UART0 Rx is Alt Input 1 on GPIO_3.0 // UART0 Tx is Alt Output 2 on GPIO_3.1 // // Board is operating at 48 Mhz and the BRDi and BRDf registers // are set up to generate a baudrate of 115,200. //*********************************************************************** #include <91x_lib.h> #include "LCD.h" int sendchar(int ch); int retval; int main (void) { unsigned int i; SCU->GPIOOUT[7] = 0x5555; /* P7.0..7 output - mode 1 */ GPIO7->DDR = 0xFF; /* P7.0..7 Outputs (LED Data) */ /* LCD Setup......................................................*/ GPIO8->DDR = 0xFF; /* P8.0..7 Outputs (LCD Data) */ GPIO9->DDR = 0x07; /* P9.0..2 Outputs (LCD Control) */ /* UART1 Setup.....................................................*/ SCU->GPIOOUT[3] &= 0xFF3F; /* Enable UART0_TX (COM1) connected to P3.1 */ /* by setting bits 6 & 7 to 0 first */ SCU->GPIOOUT[3] |= 0x0080; /* then by setting bit 7 to 1 */ /* this sets GPIOOUT[3] to "Alternate Output 2" */ SCU->GPIOIN[3] |= 0x01; /* Enable UART0_RX (COM1) connected to P3.0 */ /* by setting bit 0 to 1 */ /* this sets GPIOIN[3] to "Alternate Input 1" */ UART0->IBRD = 0x1A; /* Integer divider for 115kBaud */ UART0->FBRD = 0x03; /* Fractional divider */ UART0->LCR = 0x0060; /* 8 bits, no Parity, 1 Stop bit, FIFO disabled */ UART0->CR = 0x0301; /* Enable UART, Receive Enable, Transmit Enable */ lcd_init(); lcd_clear(); lcd_print (" TEST.C "); /* this line of code works */ set_cursor (0, 1); lcd_print (" Sept. 30, 2006 "); /* this line of code works */ /* retval=sendchar('A'); if this line is left un-commented, the code */ /* compiles and loads, but the program hangs */ for (i = 0; i < 5; i++) wait(); /* Wait for initial display */ while (1) { /* Loop forever */ int n=0; for(n=0x01;n<=0xFF;n<<=1) /* scroll thru all eight LEDS */ { GPIO7->DR[0x3FC] = n; /* Turn on LED ...this code works */ wait(); /* Delay */ /* retval=sendchar('A'); if this line is left un-commented, the code */ /* compiles and loads, but the program hangs */ } } } int sendchar (int ch) { /* Debug output to serial port. */ if (ch == '\n') { while (!(UART1->FR & 0x0080)); UART0->DR = '\r'; /* output CR */ } while (!(UART1->FR & 0x0080)); return (UART0->DR = ch); } void wait (void) { /* Wait function */ long d=950000L; /* 950,000 gives a delay of about 1 sec. */ while (d--); /* Only to delay for LED flashes */ }
Thanks in Advance, -=Rich=-
"What about SCU_PCGR1?"
Or is that something handled by the pre-main() startup code?
Dan:
Thanks for the reply. I haven't been able to implement your idea yet since I've had trouble getting to Keil's website until this morning.
I looked into my assembly startup file, and sure enough, it looks as though the UART clock gating hasn't been turned on. Heres a snippet of what I found:
SCU_PCGR1_Val EQU 0x00EC0803 . . ; lots of other code here . LDR R1, =SCU_PCGR0_Val ; Enable clock gating STR R1, [R0, #SCU_PCGR0_OFS] LDR R1, =SCU_PCGR1_Val STR R1, [R0, #SCU_PCGR1_OFS]
I'll set bit 3 when I get home from work (workin' offshore today...Gulf of Mexico oilfield) today and give it another go. Thanks so much for the help. I'll bet dollars to donuts that you identified the problem! Yours Truly Confused, -=Rich=-
I went into the assembler startup code and made sure that the peripheral gating for the UARTs was turned on. Actually, I turned on ALL the peripheral gating:
SCU_PCRG1=0xFFFFFFFF
That didn't have any effect. My code still appeared to be hanging in the
while (!(UART0->FR & 0x0080));
Next thing I tried was to make sure that none of the UARTS (or any perhipheral the UART depends on) was "held in reset". I did this by setting SCU_PRR1=0xFFFFFFFF Interestingly enough, that stopped the code from hanging in the aforementioned while loop. However, I still am not getting any output from the UART. Any suggestions? My latest code follows:
//*************************** TEST.C ************************************ // Auth: R. McCoy // Date: 9/24/2006 // Gist: Blinks LEDS on port 7 of Keil MCBSTR9 board. Also TRYING to spit a // character ('A') out of COM1 (UART0). // Note: It appears that there is an error in the documentation on page 78 of // ST Manual UM0216 (STR91x Reference manual). The SCU_GPOINn register // documentation makes no sense whatsoever. Only 8 bits are shown...not // the 16 bits that should be depicted. Also, why does the table jump from // pin3 to pin7 (going right to left)? // Stat: No luck so far. // // Targ: Using the Keil MCBSTR9 Demo Board: // COM1 is connected to pins P3.0 (Rx) and P3.1 (TX) // COM2 is connected to pins P3.2 (Rx) and P3.3 (TX) // // Per Table 4 of the Str91xF (ARM966E-S) datasheet (STR912FW44.pdf): // UART0 Rx is Alt Input 1 on GPIO_3.0 // UART0 Tx is Alt Output 2 on GPIO_3.1 // // Board is operating at 48 Mhz and the BRDi and BRDf registers // are set up to generate a baudrate of 115,200. //*********************************************************************** #include <91x_lib.h> #include "LCD.h" int sendchar(int ch); int retval; void wait (void){ /* Wait function */ long d=950000L; /* 950,000 gives a delay of about 1 sec. */ while (d--); /* Only to delay for LED flashes */ } int main (void) { unsigned int i; SCU->GPIOOUT[7] = 0x5555; /* P7.0..7 output - mode 1 */ GPIO7->DDR = 0xFF; /* P7.0..7 Outputs (LED Data) */ /* LCD Setup......................................................*/ GPIO8->DDR = 0xFF; /* P8.0..7 Outputs (LCD Data) */ GPIO9->DDR = 0x07; /* P9.0..2 Outputs (LCD Control) */ /* UART1 Setup.....................................................*/ SCU->GPIOOUT[3] &= 0xFF3F; /* Enable UART0_TX (COM1) connected to P3.1 */ /* by setting bits 6 & 7 to 0 first */ SCU->GPIOOUT[3] |= 0x0080; /* then by setting bit 7 to 1 */ /* this sets GPIOOUT[3] to "Alternate Output 2" */ SCU->GPIOIN[3] |= 0x01; /* Enable UART0_RX (COM1) connected to P3.0 */ /* by setting bit 0 to 1 */ /* this sets GPIOIN[3] to "Alternate Input 1" */ UART0->IBRD = 0x1A; /* Integer divider for 115kBaud */ UART0->FBRD = 0x03; /* Fractional divider */ UART0->LCR = 0x0060; /* 8 bits, no Parity, 1 Stop bit, FIFO disabled */ UART0->CR = 0x0301; /* Enable UART, Receive Enable, Transmit Enable */ lcd_init(); lcd_clear(); lcd_print (" TEST.C "); /* this line of code works as expected */ set_cursor (0, 1); lcd_print (" October 2, 2006 "); /* this line of code works as expected*/ retval=sendchar('A'); /* This function returns */ for (i = 0; i < 5; i++) wait(); /* Wait for initial display */ while (1) { /* Loop forever */ int n=0; for(n=0x01;n<=0xFF;n<<=1) /* scroll thru all eight LEDS */ { GPIO7->DR[0x3FC] = n; /* Turn on LED ...this code works */ wait(); /* Delay */ retval=sendchar('A'); /* This function returns */ } } } int sendchar (int ch) { /* Debug output to serial port. */ if (ch == '\n') { while (!(UART0->FR & 0x0080)); /* No longer hangs in this code */ UART0->DR = '\r'; /* No output! */ } while (!(UART0->FR & 0x0080)); /* No longer hangs in this code */ return(UART0->DR = ch); /* No output! */ // The "improvement" over the last revision seems to be due to the change of // the folloing registers: // SCU_PRCG1=0xFFFFFFFF ...turns on peripheral gating to all peripherals // SCU_PRR1=0xFFFFFFFF ...takes all peripherals "out of reset" ...as opposed // to "holding them in reset" }
Correction:
SCU_PCRG1=0x01FFFFFF
SCU_PRR1=0x01FFFFFF
Didn't make any difference though since bits 31:25 are reserved (always read as zero).
UART still doesn't spit out any characters! Arrgh.
Best Regards,
-=Rich=-
We've selected the STR912FW44 for one of our next designs and although we've successfully implemented another manufacturer's ARM9 MCU in a different design, only a small percentage of that experience can be utilized in this next ARM9 design. As you know, a core is a core, but the peripheral subsystems that manufacturers bolt on do differ. So without benefit of having a MCBSTR9 board on my bench, I'm working blind and just throwing out ideas (e.g., the clock gating thing bit me with the 'other' ARM9 MCU's Ethernet MAC acting dead).
Anyhow, our dialog has me wondering; didn't the Keil board come with example code for UART comms? If so, is it downloadable for my inspection? Did the Keil board come with a schematic that I could refer to and understand how GPIO interacts with UART operations, or is just a matter of me not reading the UM0216 Reference Manual closely enough since I'm not quite yet motivated (i.e., scheduled) to do so?
Here's the link to the MCBSTR9 schematic (pdf form):
http://www.keil.com/mcbstr9/mcbstr9-schematics.pdf
As I understand it, you have to set up several registers in the assembly startup file. These seem to relate primarily to clock speeds, clock gating, power, and reset state.
The setting up of the UART(s) can be done mostly in C code. This include the setting of the modes (parity, stop bits, etc.) as well as baud rate (integer divisor, fractional divisor), and enable/disable. This code is in my original post.
The answer to your question regaring whether Keil supplied a serial comm example is not so straightforward. The two examples provided were BLINKY (excercises timer, LCD, ADC, and LEDS) and a webserver written by a third party (Easyweb is what I think it was called). These were located in a directory C:\Keil\ARM\RV30\Boards\Keil\MCBSTR9
Keil also supplied a number of examples from ST (for example C:\Keil\ARM\RV30\Examples\ST\STR91xLib\UART\EXAMPLE1)
It appears that this example is set up for some sort of demo board made by ST since it uses GPIO ports 5,3, and 2 for Rx, TX, RTS, and CTS respectively. Given the the MCBSTR9 board only uses pins from GPIO3 (TX and RX only), I didn't try to run the example on my Keil board.
In the course of making a decision to go with the STR9, I asked Keil if they could send me one of the examples from the RTL kit (RTOS, TCP/IP, etc) so that I could get a feel for the level of effort required to use the TCP/IP stack. The example, LEDSwitch.C, sets up a client that switches an LED in response to TCP packets sent from a PC. Besides switching the LED, it sends a message out the serial port.
Now, to the point...It is this piece of code that I modified to create the program I originally posted.
But to answer your question directly: No Keil didn't provide a UART example. Nor do they seem inclined to do so. In several e-mail exchanges with Keil, their tech support guy said that he/they didn't have time to provide one and that if I or ST could tell them which registers to modify, he could tell me how to do that using the Keil tools. Apparently, Keil doesn't know which registers to set up to make a STR9 UART work either.
On a positive note; I'm glad to see that you are going to be using STR9 as well. I was beginning to think I was the only one who was using the chip/board!
Thanks Again,
OK, next guess...
Seems like for UART0, your GPIOOUT[3] LSB's nibbles are transposed. Shouldn't it be?:
SCU->GPIOOUT[3] &= 0xFFF3; SCU->GPIOOUT[3] |= 0x0008;
I have a sneaking suspicion that you're right! I'm looking at the ST document 12274.pdf on page 39 and it looks like I definitely need to set P3.1 to "Alternate Output 2". That said, page 78 in ST document 112126.pdf says to set bits 3:2 to 1 and 0 respectively (0x08). I'll check it out tonight and revert in the A.M.
Thanks so much!
All:
Dan made the call when he spotted that I had transposed nibbles. After making the suggested correction the code ran just fine.
The following is the working code (for the benefit of anyone else that was having similar problems)
//*************************** TEST.C ************************************ // Auth: R. McCoy // Date: 10/5/2006 // Gist: Blinks LEDS on port 7 of Keil MCBSTR9 board. Also spits a // character ('A') out of COM1 (UART0). // Note: It appears that there is an error in the documentation on page 78 of // ST Manual UM0216 (STR91x Reference manual). The SCU_GPOINn register // documentation makes no sense whatsoever. Only 8 bits are shown...not // the 16 bits that should be depicted. Also, why does the table jump from // pin3 to pin7 (going right to left)? // Stat: Works fine. // // Targ: Using the Keil MCBSTR9 Demo Board: // COM1 is connected to pins P3.0 (Rx) and P3.1 (TX) // COM2 is connected to pins P3.2 (Rx) and P3.3 (TX) // Both ports are set up as DCE. This means you DON'T need a Null Modem // cable. A DB-9 straight-thru works just fine. // // Per Table 4 of the Str91xF (ARM966E-S) datasheet (STR912FW44.pdf): // UART0 Rx is Alt Input 1 on GPIO_3.0 // UART0 Tx is Alt Output 2 on GPIO_3.1 // // Board is operating at 48 Mhz and the BRDi and BRDf registers // are set up to generate a baudrate of 115,200. // // Warn: This file does not contain "production" code. It is written for // testing purposes only. AS A RESULT, NEITHER RICHARD MCCOY NOR HIS EMPLOYER // SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES // WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT OF SUCH SOFTWARE AND/OR // THE USE MADE BY OTHERS OF THE CODING INFORMATION CONTAINED HEREIN IN // CONNECTION WITH THEIR PRODUCTS. //*********************************************************************** #include <91x_lib.h> #include "LCD.h" int sendchar(int ch); int retval; void wait (void){ /* Wait function */ long d=950000L; /* 950,000 gives a delay of about 1 sec. */ while (d--); /* Only to delay for LED flashes */ } int main (void) { unsigned int i; SCU->GPIOOUT[7] = 0x5555; /* P7.0..7 output - mode 1 */ GPIO7->DDR = 0xFF; /* P7.0..7 Outputs (LED Data) */ /* LCD Setup......................................................*/ GPIO8->DDR = 0xFF; /* P8.0..7 Outputs (LCD Data) */ GPIO9->DDR = 0x07; /* P9.0..2 Outputs (LCD Control) */ /* UART0 Setup.....................................................*/ SCU->GPIOOUT[3] &= 0xFFF3; /* Enable UART0_TX (COM1) connected to P3.1 */ /* by setting bits 3 & 2 to 0 first */ SCU->GPIOOUT[3] |= 0x0008; /* then by setting bit 3 to 1 */ /* this sets GPIOOUT[3] to "Alternate Output 2" */ /* see page 78 of ST Microelectronics Document */ /* UM0216 (12126.pdf) for info on this register */ /* see page 39 of ST Microelectronics 12274.pdf- */ /* STR91xF Data Sheet for information on alternate */ /* pin functions */ SCU->GPIOIN[3] |= 0x01; /* Enable UART0_RX (COM1) connected to P3.0 */ /* by setting bit 0 to 1 */ /* this sets GPIOIN[3] to "Alternate Input 1" */ /* Baud rate integer and fractional divisors were */ /* calculated based on the Baud Rate Clock being */ /* set to fMSTR (as opposed to fMSTR/2). */ UART0->IBRD = 0x1A; /* Integer divider for 115kBaud */ UART0->FBRD = 0x03; /* Fractional divider */ UART0->LCR = 0x0060; /* 8 bits, no Parity, 1 Stop bit, FIFO disabled */ UART0->CR = 0x0301; /* Enable UART, Receive Enable, Transmit Enable */ lcd_init(); lcd_clear(); lcd_print (" TEST.C "); /* this line of code works as expected */ set_cursor (0, 1); lcd_print (" October 5, 2006 "); /* this line of code works as expected*/ retval=sendchar('A'); /* This function returns */ for (i = 0; i < 5; i++) wait(); /* Wait for initial display */ while (1) { /* Loop forever */ int n=0; for(n=0x01;n<=0xFF;n<<=1) /* scroll thru all eight LEDS */ { GPIO7->DR[0x3FC] = n; /* Turn on LED ...this code works */ wait(); /* Delay */ retval=sendchar('A'); /* This function returns */ } } } int sendchar (int ch) { /* Debug output to serial port. */ if (ch == '\n') { while (!(UART0->FR & 0x0080)); UART0->DR = '\r'; } while (!(UART0->FR & 0x0080)); return(UART0->DR = ch); }
I should add that it took some time to figure out that several registers must be modified in the ST91x.s startup file. In particular were the: 1.) Clock control register (SCU_CLKCNTR) 2.) Peripheral Gate Control register (SCU_PCGR1) 3.) Peripheral Reset register (SCU_PRR1) If you don't have these set correctly, the UART won't work. I strongly suggest using the "Configuration Wizard" to modify your startup file. But, by all means, read the docs as well. Good Luck to all and a special thanks to Dan Henry. He's the one responsible for my still having some hair left! -=Rich=-
That's great news Rich! Thanks for closing the loop and for the acknowledgement.