Hi dear Keil fellows,
I am developping a SD card bootloader based on the app note AN10835: LPC2000 Secondary bootloader. I don't need the menu and the command set to match the requirements of my application, but I think that displaying messages on the UART is a good way to get an easy debug monitoring. To achieve this goal I use the retarget.c and serial.c files provided with the app note but I am not able to get any frame I am supposed to send on my terminal.
I made many in-depth searchs over the inernet and in the LPC23xx user manual without success. I've seen few errors in the init_serial function so I modified it to match NXP's instructions.
The original init_serial:
/*---------------------------------------------------------------------------- * init_serial: Initialize Serial Interface *---------------------------------------------------------------------------*/ /* init UART1, 115200/8/N/1, suppose PCLK=12MHz, */ void init_serial () { /* Initialize the serial interface */ /* Configure UART1 for 115200 baud. */ PINSEL0 &= ~0xC0000000; PINSEL0 |= 0x40000000; /* Enable TxD1 pin */ PINSEL1 &= ~0x00000003; PINSEL1 |= 0x00000001; /* Enable RxD1 pin */ U1LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit*/ U1DLL = 3; /* for 12MHz PCLK Clock */ U1FDR = 0x67; /* Fractional Divider */ U1LCR = 0x03; /* DLAB = 0 */ }
The one I use now:
/*---------------------------------------------------------------------------- * init_serial: Initialize Serial Interface *---------------------------------------------------------------------------*/ /* init UART1, 115200/8/N/1, suppose PCLK=12MHz, */ void init_serial () { /* Initialize the serial interface */ /* Configure UART1 for 115200 baud. */ PINSEL0 &= ~0xC0000000; PINSEL0 |= 0x40000000; /* Enable TxD1 pin */ PINSEL1 &= ~0x00000003; PINSEL1 |= 0x00000001; /* Enable RxD1 pin */ U1LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit*/ U1DLL = 4; /* for 12MHz PCLK Clock */ U1FDR = 0x85; /* Fractional Divider */ U1LCR &= 0x7F; /* DLAB = 0 */ }
NB: Those values are from LPC23xx user manual page 455.
I was suspecting an issue with the retargeting of printf so I made a little funcion I called uprintf to not call printf.
/*---------------------------------------------------------------------------- * uprintf: Print a string on Serial Port *---------------------------------------------------------------------------*/ void uprintf ( const char *buf , char len ) { for( ; len ; len--) sendchar (*buf++); }
I use this function in combination with sprintf:
char len; char buf[128]; len = sprintf(buf, "\n> Initializing SD/MMC Card : "); uprintf(buf, len);
Even with this method I don't have anything on my terminal. I managed to monitor the TXD1 pin with an oscilloscope but the pin remains tied to high level so I ask to know if you guys have any idea of what is going on or what I am doing wrong ?
My target is a LPC2388 and I develop with µvision 4.02 and RL-ARM 3.4 if it can help.
Thanks in advance for your help :)
Kind regards.
I add the retarget.c and the serial.c files I am using for now.
Retarget.c file:
#include <stdio.h> #include <string.h> #include <rt_misc.h> #include <rt_sys.h> #include "File_Config.h" #pragma import(__use_no_semihosting_swi) /* The following macro definitions may be used to translate this file: STDIO - use standard Input/Output device (default is NOT used) */ /* Standard IO device handles. */ #define STDIN 0x8001 #define STDOUT 0x8002 #define STDERR 0x8003 /* Standard IO device name defines. */ const char __stdin_name[] = "STDIN"; const char __stdout_name[] = "STDOUT"; const char __stderr_name[] = "STDERR"; struct __FILE { int handle; /* Add whatever you need here */ }; /* STDIOÔÚÎļþRetarget.cµÄoptionsÀïÉèÖà */ #ifdef STDIO extern int sendchar (int ch); extern int getkey (void); #endif /*--------------------------- _ttywrch --------------------------------------*/ void _ttywrch (int ch) { #ifdef STDIO sendchar(ch); #endif } /*--------------------------- _sys_open -------------------------------------*/ FILEHANDLE _sys_open (const char *name, int openmode) { /* Register standard Input Output devices. */ if (strcmp(name, "STDIN") == 0) { return (STDIN); } if (strcmp(name, "STDOUT") == 0) { return (STDOUT); } if (strcmp(name, "STDERR") == 0) { return (STDERR); } return (__fopen (name, openmode)); } /*--------------------------- _sys_close ------------------------------------*/ int _sys_close (FILEHANDLE fh) { if (fh > 0x8000) { return (0); } return (__fclose (fh)); } /*--------------------------- _sys_write ------------------------------------*/ int _sys_write (FILEHANDLE fh, const U8 *buf, U32 len, int mode) { #ifdef STDIO if (fh == STDOUT) { /* Standard Output device. */ for ( ; len; len--) { sendchar (*buf++); } return (0); } #endif if (fh > 0x8000) { return (-1); } return (__write (fh, buf, len)); } /*--------------------------- _sys_read -------------------------------------*/ int _sys_read (FILEHANDLE fh, U8 *buf, U32 len, int mode) { #ifdef STDIO if (fh == STDIN) { /* Standard Input device. */ for ( ; len; len--) { *buf++ = getkey (); } return (0); } #endif if (fh > 0x8000) { return (-1); } return (__read (fh, buf, len)); } /*--------------------------- _sys_istty ------------------------------------*/ int _sys_istty (FILEHANDLE fh) { if (fh > 0x8000) { return (1); } return (0); } /*--------------------------- _sys_seek -------------------------------------*/ int _sys_seek (FILEHANDLE fh, long pos) { if (fh > 0x8000) { return (-1); } return (__setfpos (fh, pos)); } /*--------------------------- _sys_ensure -----------------------------------*/ int _sys_ensure (FILEHANDLE fh) { if (fh > 0x8000) { return (-1); } return (__flushbuf (fh)); } /*--------------------------- _sys_flen -------------------------------------*/ long _sys_flen (FILEHANDLE fh) { if (fh > 0x8000) { return (0); } return (__get_flen (fh)); } /*--------------------------- _sys_tmpnam -----------------------------------*/ int _sys_tmpnam (char *name, int sig, unsigned maxlen) { return (1); } /*--------------------------- _sys_command_string ---------------------------*/ char *_sys_command_string (char *cmd, int len) { return (cmd); } /*--------------------------- _sys_exit -------------------------------------*/ void _sys_exit (int return_code) { /* Endless loop. */ while (1); } /*---------------------------------------------------------------------------- * end of file *---------------------------------------------------------------------------*/
Serial.c file:
#include <LPC23xx.h> /* LPC23xx definitions */ /*---------------------------------------------------------------------------- * init_serial: Initialize Serial Interface *---------------------------------------------------------------------------*/ /* init UART1, 115200/8/N/1, suppose PCLK=12MHz, */ void init_serial () { /* Initialize the serial interface */ /* Configure UART1 for 115200 baud. */ PINSEL0 &= ~0xC0000000; PINSEL0 |= 0x40000000; /* Enable TxD1 pin */ PINSEL1 &= ~0x00000003; PINSEL1 |= 0x00000001; /* Enable RxD1 pin */ U1LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit*/ U1DLL = 4; /* for 12MHz PCLK Clock */ U1FDR = 0x85; /* Fractional Divider */ U1LCR &= 0x7F; /* DLAB = 0 */ } /*---------------------------------------------------------------------------- * sendchar: Write a character to Serial Port *---------------------------------------------------------------------------*/ int sendchar (int ch) { if (ch == '\n') { while (!(U1LSR & 0x20)); U1THR = '\r'; } while (!(U1LSR & 0x20)); return (U1THR = ch); } /*---------------------------------------------------------------------------- * getkey: Read a character from Serial Port *---------------------------------------------------------------------------*/ int getkey (void) { while (!(U1LSR & 0x01)); return (U1RBR); } /*---------------------------------------------------------------------------- * uprintf: Print a string on Serial Port *---------------------------------------------------------------------------*/ void uprintf ( const char *buf , char len ) { for( ; len ; len--) sendchar (*buf++); } /*---------------------------------------------------------------------------- * end of file *---------------------------------------------------------------------------*/
Not sure how the SD card plays into the UART not working.
Make sure you're clocking at 12 MHz, and not something else, otherwise all the math fails. The UART also uses CMOS levels, not RS232, so consider how it is wired. If you need to confirm the baud rate send a continuous stream (0x55, or 0xAA for example) and confirm the bit timings on a scope.
// (((12000000 / 16) * 5) / 8) / 4 = 117187.5 (+1.7%) UxFDR = 0x85; /* Fractional divider 5/8 */ UxLCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ UxDLL = 4; /* 115200 Baud Rate @ 12.0 MHZ PCLK */ UxDLM = 0; /* High divisor latch = 0 */ UxLCR = 0x03; /* DLAB = 0 */
You could also use the fact that C strings are NUL terminated
void uputs ( const char *buf) { while(*buf) sendchar (*buf++); }
Hello Pier,
Thank you for your answer.
First of all, I am 100% sure that I run at PCLK = 12MHz. My problem isn't the baudrate, I just can't get anyhing out of my UART.
I think this is a retargeting issue, but I don't understand how and why, I am not used to this technique. I am using serial.c and retarget.c files which are supposed to work well "out of the box" and I don't know why it is not the case.
Regards.
Then ignore all the retargeting clutter and focus on a simple demo where you enable the UART in main() and send a stream of characters in a loop. There is no point proceeding until you can get that working.
Is this on some regular eval board, or a custom board? Provide some more details. Check the UART and pin assignments.