LPC812 UART ROM driver

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC812 UART ROM driver

4,319 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Helmut Stettmaier on Wed Jan 02 06:22:54 MST 2013
Hello,
at first let me whish a "Happy New Year" to all of you.

I want to start a becoming-familiar-project for the LPC800 (my first ARM:-) using the UART. Of course I want to use the driver in the device's ROM, but this turns out to be a bit complicated.
Can anybody please tell me where I can find more detailed descriptions or even tutorials of the ROM drivers extending and completing the notes in the "LPC800 User manual", Rev. 1.0 (UM10601)? (Ok, I understand, this is a draft, but perhaps you are interested in one more proof reader?)

As the UART driver is most likely used by ISP I think that it is tested and that it works. Checking and reading what I could find yielded some questions.

1. Is uart_get_char() really blocking? Is uart_get_line also blocking (nothing said explicitely in chapter 24.4.6, only the existence of the error message "ERR_UART_RECEIVE_ON - UART receive is ongoing" lets me take some hope that it doesn't block).

2. How can I "watch" the serial line until a block of bytes has been received?
"Blocks" in this context are byte sequences separated by pauses (HI level) of at least one byte duration, so a block is catched by awaiting & reading a stream, an IDLE-event and then counting the length of the received data. Blocks can be longer than the ones I'm interested in, so more than [I]n[/I] bytes need not to be buffered, I just await the pause in such cases.
I have already programmed this for another processor, this question however concentrates on how to do this using the ROM drivers.

3. Does uart_get_mem_size return a fixed number? May I use a fixed, statically allocated block as long I am sure of the driver version? I do NOT want to use malloc() or something similar.

4. If I cannot use the driver or, more likely, if I must extend it by application code: I could not find a definition [B]when[/B] the RX enters idle mode: Immediately after scanning the stop bit or after some additional time. Or must I use a timer to detect the pause after a block?

Hmmm, a bit of a chunk for my first question... Thank you for your attention and your time!
Helmut
0 Kudos
Reply
19 Replies

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by rw_ on Fri Jan 04 17:36:23 MST 2013

Quote: Helmut Stettmaier
Hello,
at first let me whish a "Happy New Year" to all of you.



Happy New Year to you too!


Quote: Helmut Stettmaier
I want to start a becoming-familiar-project for the LPC800 (my first ARM:-) using the UART. Of course I want to use the driver in the device's ROM, but this turns out to be a bit complicated.



I'm glad to hear that you're using the LPC8xx as your first ARM part.  I hope that you'll like it as much as I do!


Quote: Helmut Stettmaier
Can anybody please tell me where I can find more detailed descriptions or even tutorials of the ROM drivers extending and completing the notes in the "LPC800 User manual", Rev. 1.0 (UM10601)? (Ok, I understand, this is a draft, but perhaps you are interested in one more proof reader?)



Interestingly, I'm currently working on the same code.  A ROM-API based driver for the UART.  Perhaps we can share some information about it here?


Quote: Helmut Stettmaier
As the UART driver is most likely used by ISP I think that it is tested and that it works. Checking and reading what I could find yielded some questions.



I was able to get the ROM-API UART working.  Hopefully, this effort will help answer some of your questions.  I don't yet know what I don't know about it :)


Quote: Helmut Stettmaier
1. Is uart_get_char() really blocking? Is uart_get_line also blocking (nothing said explicitely in chapter 24.4.6, only the existence of the error message "ERR_UART_RECEIVE_ON - UART receive is ongoing" lets me take some hope that it doesn't block).



As far as I understand it, #1 yes, uart_get_char is really "blocking."  It is a "polled only" mode function that, once setup/configured/initialized, works very much the same as a non-ROM based driver, but without having to manually check the RXRDY/RXIDLE bits yourself.  Additionally, if a byte in not received, it will block indefinitely waiting for a byte once called.  I have tested this in my own code where I call it with a breakpoint on the call and another breakpoint after the call.  It will not reach the later BP until after I "send" a character from my terminal program to the LPC8xx.  This is also the case when calling get_line in "polling" mode.  Interrupt mode is the key to not blocking.


Quote: Helmut Stettmaier
2. How can I "watch" the serial line until a block of bytes has been received?
"Blocks" in this context are byte sequences separated by pauses (HI level) of at least one byte duration, so a block is catched by awaiting & reading a stream, an IDLE-event and then counting the length of the received data. Blocks can be longer than the ones I'm interested in, so more than n bytes need not to be buffered, I just await the pause in such cases. 



I don't know if I have a "real" answer for you with regard to the specific elements posed by your question and objective(s).  I can offer what I *think* about it based on what I've learned so far, but I don't yet know if it is true or not for sure without further testing and coding to see if what I think is how it works.

Basically, you will want to implement your callbacks per the following signature:

typedef void (*UART_CALLBK_T)(uint32_t err_code, uint32_t n);

In my examples/tests, I simply created one for each of receive data and transmit data.  While perhaps not very original, I arbitrarily used rx_callback and tx_callback.  I haven't yet figured out a way to use a single callback for both RX and TX needs, but perhaps I will? :)

During your configuration of the put_line or get_line, the parameter argument needs to have the callback specified and the "transfer or receive mode" (transfer_mode member of the UART_PARAM_T structure and, of course, the "driver_mode" member needs to be 0x01 for "interrupt mode."

Additionally, you will want to enable the UARTn_IRQ in the NVIC before passing the parameter in on the put/get_line ROM calls, else no interrupt will fire.  In your ISR for the UART, you will want to call the uart_isr passing the respective handle for the given UART that you received back from the API when you called uart_setup.  That will then invoke the callback respective for the rx or tx that you passed in your "param" argument to the get/put_line function.

In order to "watch" it, you may have to configure your buffer for over/under run sizing such that you can force the eventuality that you expect/desire and then process the condition in the callback with the error_en bit(s) set per your needs.


Quote: Helmut Stettmaier
I have already programmed this for another processor, this question however concentrates on how to do this using the ROM drivers.



I *may* be able to help you through your specific effort, but if not, perhaps some of my reply may help you understand it better?  Please let me know if you need any clarification of my points.


Quote: Helmut Stettmaier
3. Does uart_get_mem_size return a fixed number? May I use a fixed, statically allocated block as long I am sure of the driver version? I do NOT want to use malloc() or something similar.



My experiences indicate that, for at least the part I'm working with and the ROM driver version in the chip, the size returned by get_mem_size is fixed at 0x20 bytes.  I'm not exactly sure whether there is any value to ever calling it unless it is to see if perhaps the size changed in some future release and whether or not your code will break as a result.


Quote: Helmut Stettmaier
4. If I cannot use the driver or, more likely, if I must extend it by application code: I could not find a definition when the RX enters idle mode: Immediately after scanning the stop bit or after some additional time. Or must I use a timer to detect the pause after a block?



I think that you'll want to configure for interrupt driven mode using the buffer size that meets your needs for the kind of transfers you're expecting and then enable to various error bits in the UART_CONFIG_T structure (error_en member) so that you will receive a callback from the corresponding interrupt sources/INTENSET such as OVERRUNEN, DELTARXBRKEN or "under run" (when receiving less than a full "buffer") and that by doing these configurations and handling the various states using status bits in your callback, you should be able to achieve your objectives.  Note that I prefaced all of this with "I think" :)  I am still experimenting with some of the finer-grained uses of the ROM API.

My first thought is that when the RX enters the idle state, assuming no error state, that the callback would be fired


Quote: Helmut Stettmaier
Hmmm, a bit of a chunk for my first question... Thank you for your attention and your time!
Helmut



Yes, it is a bit of a chunk for your first few questions :D  ...but after working through it and getting it working for my needs, I can appreciate the effort.

rw_
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vsluiter on Thu Aug 22 12:27:16 MST 2013
Hello Marcus,
Thanks a lot! I already got the code working; after my previous post I put another post here, which I edited later to show what I made. Unfortunately that edit meant including a URL, and now it has disappeared from this site as probably someone has to say that it's OK. I hope it will be posted here soon. If not, please check site: hackvandedam. nl
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by abj1819 on Tue Aug 20 19:33:00 MST 2013
Hi Victor,

  It could be blocked if you set driver_mode=0 (pollin mode).
  Here is the brief code for 'uart_get_line', hope it could be helpful.
      uint32_t uart_get_line(UART_HANDLE_T handle, UART_PARAM_T * param){
if ((param->transfer_mode >= 3) || (param->driver_mode >= 3)) return ERR_UART_PARAM;
//clean up rxd buffer
empty_rxd_buffer((UART_DRIVER_TypeDef *)handle);
if (param->driver_mode == 0){ // polling mode
((UART_DRIVER_TypeDef *)handle)->callback_rxd = NULL;
                //polling all data has beene received or error happened
while(((UART_DRIVER_TypeDef *)handle)->mode_rxd != 0xFF){
uart_isr((UART_DRIVER_TypeDef *)handle);
}//while
param->size =  ((UART_DRIVER_TypeDef *)handle)->num_rxd; //numbler of data has been received
return ((UART_DRIVER_TypeDef *)handle)->max_rxd_err; //return error code
}
else if ((param->driver_mode == 1) && (param->callback_func_pt != NULL)){ // Intr mode
((UART_DRIVER_TypeDef *)handle)->callback_rxd = param->callback_func_pt;
//enable rxd and rxd error INT
((UART_DRIVER_TypeDef *)handle)->base_addr->INTENSET = RXRDY | ((((UART_DRIVER_TypeDef *)handle)->error_en << 8)
                                                                       & RXDERR);
return LPC_OK;
}

else
return ERR_UART_PARAM;
     }//uart_get_line

Thanks,
Marcus
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vsluiter on Tue Aug 20 05:47:58 MST 2013
OK, I got the UART ROM driver working as good as I can;
The only problem I face is that when I use uart_get_line it only goes to its callback function when the buffer is full, even when I use RX_MODE_CRLF_RECVD as transfer mode. This is my setup code:
param.buffer = (uint8_t *) PoVstring_ram;
param.size = sizeof(PoVstring_ram);
param.transfer_mode = RX_MODE_CRLF_RECVD;
param.driver_mode = DRIVER_MODE_INTERRUPT;
param.callback_func_pt = (UART_CALLBK_T)rx_callback;
LPC_UART_API->uart_get_line(uart, &param);

The received characters are stored in the correct location, I can verify that, and the right callback function is also called, but as I said only when the buffer is full. Can anyone verify this behavior, or tell me what I've done wrong?

Greetings,
Victor
Edit: Again, I'll answer myself, to help others encountering the same error. I was using minicom as terminal emulator, which only sends CR, and no LF. I'm now using seyon, which has the possibility to send CR+LF
Edit2: For those interested: this is the this is the finished prototypelink to the git repository
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vsluiter on Sun Aug 18 15:23:16 MST 2013
Hello Ken,

That helped a lot, I've taken out the bits and pieces I needed. I do have a question about the 'uart_get_line' function though; is it a blocking function or not? And does it return zero when it has no error? Is it possible to start this function and monitor a flag / variable to see when a complete message has arrived (I'm OK with a LF terminated string)

Sorry  for all these questions, but the documentation in the User Manual for LPC81x lacks some explanation...

Edit: I've come this far: it's not blocking, and I need to use a callback function to let me know that a new message has been received.
Still, more documentation (pseudocode of what is in ROM?) would be appreciated!
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by usb10185 on Mon Aug 12 19:11:49 MST 2013
Hi Victor,

Have a look at LPCOpen: http://lpcware.com/content/nxpfile/lpcopen-platform

Look for in the following path: lpcopen\applications\lpc8xx\examples\periph\periph_uart_rom\

We will be releasing a smaller and dedicated LPC800 LPCOpen variant soon.

Thanks,
Ken
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vsluiter on Mon Aug 12 11:59:12 MST 2013
Hello!!
I've been experimenting with the LPC800 minikit, and now have 400 bytes of code remaining in a working application to which I would like to add some serial communication. Does anyone of you have a set of working files / code to get this going? I was in the assumption that the usermanual would be clear, or that sample code would be supplied in LPCxpresso, but haven't found examples based on the API yet. If anyone could help (or refer to one of your posts) I'd be very happy. I'll post back with my experience!

Greetings,
Victor
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lob on Sun Aug 04 08:43:10 MST 2013
Hi,

As of ROM-version 2.13, the uart_get_mem_size() returns 0x60 (96bytes)... - and looking into the bootcode its pretty hardwired ;):
address of function is 0x1fff159f (thumb-code)
asm code at 0x1fff159e:
1fff159e:       2060            movs    r0, #96 ; 0x60
1fff15a0:       4770            bx      lr

BTW I have placed a complete disassembly of the bootcode on my site - and started annotating it - but it'l take more than an afternoon - and I was going after reusable bits, like the divmod at 0x1fff1f04...
Unfortunately it seems that the bootcode is less than optimal - but if we could save a few precious bytes from the flash then...

http://midibel.com/bootrom-2.13.S

Many regards
Lars Ole
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Fri Feb 01 02:53:39 MST 2013
I realised what it was of course. As you say I'm missing * as I shouldn't be accessing 0x1FFF1FF8+0x24 but (*0x1FFF1FF8)+0x24. That is the value held at 0x1FFF1FF8 is actually 0x1FFF1EF8 and the table entry is at an offset of 0x24 from there. The 8KB  ROM is from 0x1FFF0000..0x1FFF1FFF yet I was forming address 0x1FFF201C and accessing that. 0x1C bytes beyond the end of valid memory.

Just for the record this worked (returned 40):
int main(void) {
    ROM_APIS_T ** ppROMApi;
    ROM_APIS_T * pROMApi;
    UARTD_API_T * pUartFns;
    char buff[10];

    volatile uint32_t uart_size;

    ppROMApi = (ROM_APIS_T**)0x1FFF1FF8; // pointer to base of API table
    pROMApi = *ppROMApi; // get base of API table
    pUartFns = pROMApi->uart_fns; // base of UART routines
    uart_size = pUartFns->uart_get_mem_size();
Which is just a long way of saying the same as your:
(*((void **)(DRV_TABLE_LOC))))
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Helmut Stettmaier on Thu Jan 31 13:34:28 MST 2013
Hello wrightflyer,

I'm afraid it is to be expected that such a code is generated as you use pointer variables. Could you please see how the construct with the #defined pointers is translated? I can't.

(ROM_APIS_T *)0x1FFF1FF8 is IMO one '*' short. Compare it to (working) "[FONT=Courier New](*((void **)(DRV_TABLE_LOC))))[/FONT]" in the #defines.
Sorry, I can't interpret the ldr sequence.

Kind regards,
Helmut




Edit:   Hmmm:)
(DRV_TABLE_LOC) is the number 0x1FFF1FF8.
(void *)(DRV_TABLE_LOC) points at 0x1FFF1FF8; it points at a location where the address of the beginning of the device table stands (oh god, my english... :-)), ergo
(void **)(DRV_TABLE_LOC) is the address where the device table starts. But we want to use it as a pointer, so we must write:
(*((void **)(DRV_TABLE_LOC)))) is a pointer at the device table and may be assigned or defined to pDevTable which is of type (tDevTable*).

When you use "#define pDevTable ((tDevTable*)(*((void **)(DRV_TABLE_LOC))))" you can inspect the device table and the others by positioning the mouse over pDevTable. It works. The variable display looks like this:
_ -> pDevTable       tDevTable*          0x1fff1ef8
     -> dev0         void *              0xffffffff
     -> dev1         void *              0xffffffff
     -> dev2         void *              0xffffffff
     -> devClockPo...void *              0x1fff1ee8
     (and so on)
     -> dev8         void *              0xffffffff
     -> devUART      tUARTAPI*           0x1fff1f68


The construct "((void *)(DRV_TABLE_LOC))"  (what would be equivalent to your pROMApi) is only a pointer to the location 0x1fff1ff8 in the ROM.
Try "tDevTable *pDev= ((tDevTable*)((void *)(DRV_TABLE_LOC)));".  This construct is rendered as follows:
_ -> pDev            tDevTable*          0x1fff1ff8
     -> dev0         void *              0x1fff1ef8
     -> dev1         void *              0xd01
     -> dev2         void *              
     -> devClockPo...void *              
     (and so on)
     -> dev8         void *              
     -> devUART      tUARTAPI*           

what is obviously wrong: The first entry in the "device table" is DRV_TABLE_LOC itself as stated above. It will crash.

Uff...
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Thu Jan 31 12:45:11 MST 2013
Thanks for that.

Most of the names weren't my choice - I just cut/pasted text from Chapter 20 onwards in UM10601.

However what I'm finding with the code I showed is that it generates:
   
pROMApi = (ROM_APIS_T *)0x1FFF1FF8; // base of API table
    pUartFns = pROMApi->uart_fns; // base of UART routines
    LPC_SYSCON->UARTCLKDIV = pUartFns;
 37e:    6a5a          ldr    r2, [r3, #36]    ; 0x24
 380:    4b4a          ldr    r3, [pc, #296]    ; (4ac <main+0x134>)
 382:    4c4b          ldr    r4, [pc, #300]    ; (4b0 <main+0x138>)
 384:    601a          str    r2, [r3, #0]
(the write to UARTCLKDIV is just a test write to a volatile destination to force the code to be generated - I tried making pUartFns volatile but the debugger said "optimized away" :confused:)

Anyway when it gets to 37e above R3, as expected, contains 0x1FFF1FF8 (it's give in 20.3.2 by the way ;-)) but an attempt to step the instruction so it loads R2 from that plus 0x24 leads to the Hard Fault handler being invoked. Do you have any idea why that might be? Could it be (a) there's some kind of memory protection on the ROM table/functions that I have to lift first or (b) is this one of those "Thumby" things where you don't use 0x1FFF1FF8 but something like 0x1FFF1FF9 or is that just when branching to code?
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Helmut Stettmaier on Thu Jan 31 12:11:29 MST 2013
Hello,


Quote: wrighflyer
Good idea, so does anyone know what type UART_HANDLE_T actually is?

typedef void *tUARThandle;
It points at the RAM space you must allocate for the driver (for each USART).

The dereferencing is, of course, as you layed out (I used different, more "beautiful":) names):
/** USART Treiber-Tabelle */
typedef struct sUARTAPI { // index of all the uart driver functions
  uint32_t        (*uart_get_mem_size)(void);
(as in chapter 24.4)
  void            (*uart_isr)(tUARThandle handle);
} tUARTAPI ; // end of structure

/** The device driver table. */
typedef struct sDevTable {
  void *dev0;
(as you wrote similarly)
  void *dev8;
  tUARTAPI *devUART;
} tDevTable;
I suggest to publish the 2nd table (sDevTable) in the next version of the manual to avoid confusing the positions of the pointers.

You need not to declare pointer variables, use #defines instead:
#define pDevTable ((tDevTable*)(*((void **)(DRV_TABLE_LOC))))
#define pUARTAPI ((tUARTAPI*)(pDevTable->devUART))
(I can't remember where I found [FONT=Courier New] #define DRV_TABLE_LOC 0x1fff1ff8[/FONT])

Just to see what you have done declare a variable:
tDevTable *pDev= pDevTable;
start debugging the code and view the contents of pDevTable (the constant, not necessarily the variable) to see the device table, expand devUART and see the structure you are interested in.
But, again, in general you need not to use pointer variables, you  may call any of the UART drivers like this:
uint32_t memsize= pUARTAPI->uart_get_mem_size();
I think (hope), the compiler generates quite nice code as it can dereference all the pointers at compile time; when I am fit enough with ARMs I could check the assembler code (or could please look someone else?).

ppx:  "I have not figured out if they are interrupt driven or not. Are they?"  Just read this thread.

Kind regards,
Helmut
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Thu Jan 31 10:33:33 MST 2013

Quote:
Perhaps we can share some information about it here?


Good idea, so does anyone know what type UART_HANDLE_T actually is? The documentation:

http://docs.lpcware.com/lpc800um/RegisterMaps/uartapi/r-UARTROMdrivervariables.html

says:
typedef  void     UART_HANDLE_T   ;
but that cannot be right Some of the ROM API functions take this handle as input so it cannot be void. I'm going to assume (because this is a 32bit CPU) that it's really uint32_t but what has anyone else used?

BTW I'm just doing this to get to the functions:
typedef  void     UART_HANDLE_T   ;    // define TYPE for uart handle pointer

typedef void (*UART_CALLBK_T)(void);

typedef struct { // parms passed to uart driver function
    uint8_t  *  buffer ; // The pointer of buffer.
        // For uart_get_line function, buffer for receiving data.
        // For uart_put_line function, buffer for transmitting data.
    uint32_t   size;     // [IN] The size of buffer.
        //[OUT] The number of bytes transmitted/received.
    uint16_t    transfer_mode ;
        // 0x00:  For uart_get_line function, transfer without
        //  termination.
        // For uart_put_line function, transfer without termination.
        // 0x01:  For uart_get_line function, stop transfer when
        // <CR><LF> are received.
        // For uart_put_line function, transfer is stopped after
        // reaching \0. <CR><LF> characters are sent out after that.
        // 0x02:  For uart_get_line function, stop transfer when <LF>
        // is received.
        // For uart_put_line function, transfer is stopped after
        // reaching \0. A <LF> character is sent out after that.
        //0x03:  For uart_get_line function, RESERVED.
        // For uart_put_line function, transfer is stopped after
        // reaching \0.
    uint16_t   driver_mode;
        //0x00: Polling mode, function is blocked until transfer is
        // finished.
        // 0x01: Intr mode, function exit immediately, callback function
        // is invoked when transfer is finished.
        //0x02: RESERVED
    UART_CALLBK_T     callback_func_pt; // callback function
}  UART_PARAM_T  ;

typedef struct {
    uint32_t sys_clk_in_hz; // Sytem clock in hz.
    uint32_t baudrate_in_hz; // Baudrate in hz
    uint8_t  config; //bit1:0
        // 00: 7 bits length, 01: 8 bits lenght, others: reserved
        //bit3:2
        //   00: No Parity, 01: reserved, 10: Even, 11: Odd
        //bit4
        //   0: 1 Stop bit, 1: 2 Stop bits
    uint8_t sync_mod;  //bit0: 0(Async mode), 1(Sync mode)
        //bit1: 0(Un_RXD is sampled on the falling edge of SCLK)
        //        1(Un_RXD is sampled on the rising edge of SCLK)
        //bit2: 0(Start and stop bits are transmitted as in asynchronous //mode)
        //        1(Start and stop bits are not transmitted)
        //bit3: 0(the UART is a slave on Sync mode)
        //        1(the UART is a master on Sync mode)
    uint16_t error_en; //Bit0: OverrunEn, bit1: UnderrunEn, bit2: FrameErrEn,
       // bit3: ParityErrEn, bit4: RxNoiseEn
} UART_CONFIG_T;

typedef struct  UARTD_API {         // index of all the uart driver functions
    uint32_t (*uart_get_mem_size)(void);
    UART_HANDLE_T (*uart_setup)(uint32_t base_addr, uint8_t *ram);
    uint32_t (*uart_init)(UART_HANDLE_T handle, UART_CONFIG_T *set);
    //--polling functions--//
    uint8_t (*uart_get_char)(UART_HANDLE_T handle);
    void (*uart_put_char)(UART_HANDLE_T handle, uint8_t data);
    uint32_t (*uart_get_line)(UART_HANDLE_T handle, UART_PARAM_T * param);
    uint32_t (*uart_put_line)(UART_HANDLE_T handle, UART_PARAM_T * param);
    //--interrupt functions--//
    void (*uart_isr)(UART_HANDLE_T handle);
} UARTD_API_T  ;             // end of structure

typedef struct {
    void * reserved1; //+0
    void * reserved2; //+4
    void * reserved3; //+8
    void * power_fns; //+C
    void * reserved4; //+10
    void * i2c_fns;   //+14
    void * reserved5; //+18
    void * reserved6; //+1C
    void * reserved7; //+20
    UARTD_API_T * uart_fns; //+24
} ROM_APIS_T;
then, for example:
int main(void) {
    ROM_APIS_T * pROMApi;
    UARTD_API_T * pUartFns;

    volatile uint32_t uart_size;

    pROMApi = (ROM_APIS_T *)0x1FFF1FF8; // base of API table
    pUartFns = pROMApi->uart_fns; // base of UART routines
    uart_size = pUartFns->uart_get_mem_size();
I hope this works but does anyone have other/better ideas for dereferencing their nested structure that gives the function entry points?

(also I had to guess at UART_CALLBK_T as I couldn't find where it was documented so I assumed void (*)(void))

WF1903
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ppx on Wed Jan 30 09:48:30 MST 2013
I have not figured out if they are interrupt driven or not. Are they?

Anyway the UART example for the LPC800 is polled and fairly useless to me. And it does not use the ROM drivers.

I need to implement a simple protocoll converter where most incoming commands should be sent out on the other port but some incoming commands should execute I/O on the LPC800. In fact it should work in both directions. I have alsmost finished it on a 1124 with one HW UART and one SW UART. Moving to LPC811 because of price and two real UARTs.

I just feel that moving data between ringbuffers and let the interrupt routines handle transmit and receceive is more normal. Polling UART status and using blocking getchar, no thank you. It doesn't feel right.

Also, I have no time to wait for updated manuals.
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Helmut Stettmaier on Wed Jan 30 08:33:26 MST 2013
Hello


Quote: ppx
...But if the UART ROM drivers are so badly documented, ...

I an sure this will improve soon. And you will see in different threads that the sources are not open.


Quote: ppx
To gain a few hundred bytes?

Yes. And, as I think they do what intended, less bugs and quicker development - if and only if you need what they offer.


Quote: ppx
Is the architecture similar enough? I know there is no FIFO on 812.

Both are Cortex M0 kernels? The 812 is my first LPC, even my first ARM. And I think I like it...

Perhaps, as often, my wording sounded as I would not like the fact that there are UART-ROM-drivers or as if I look down on their design. This is in general not the case (ok, blocking getchar...). I just discovered that the UART drivers are not well suited to serve the Multiplex Sensor Data Bus MSB®.
Others might be glad not to have to code command line I/O again and again as it is ready and running in the device.
I'm curious how the I²C driver will help me.

Kind regards,
Helmut
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ppx on Wed Jan 30 02:59:56 MST 2013
I agree IAP, ISP and bootloader are really usefull. But if the UART ROM drivers are so badly documented, difficult to use and have no sourcecode; why use them. To gain a few hundred bytes?

I was thinking about trying to port e.g. the 11XX UART demo to LPC812. They are interrupt driven and use ring buffers. At least I sort of understand them. Is the architecture similar enough? I know there is no FIFO on 812.
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Helmut Stettmaier on Mon Jan 28 10:56:58 MST 2013
Hello,

"Is it really worthwhile to use the ROM drivers? What do you gain?"

UART ROM divers:
If you need the functionality they offer you may save effort and flash space - a really trivial answer.
In my personal opinion the LPC800's ROM routines are made to set up command line processors or similar. If you need that these drivers are surely ok.
My first application needs something different and there is no much sense in using these drivers ...just to use them.

Boot loader/ISP and IAP:
I will definitely use them and I think they are indispensable.

The power profile API:
There is a clock control driver; the description states that it assumes a correctly set up and running clock/PLL, just to be able to adjust the PLL. I understood it that way and could not get it running in another configuration. I think this is funny. I just ran it one time to learn how to set the PLL registers to achieve the clock rate I wanted. The driver was valuable in so far as I wouldn't have understood the PLL settings otherwise.

I²C driver: I have no experience yet. It looks complicated. I will need I²C functionality.

"...are there any other issues with LPC8XX?" Yes.
The "Preliminary user manual" UM10601 Rev. 1 — 9 November 2012 is quite incomplete, often not easy to understand and it is, I'm sorry, buggy - especially the descriptions of the ROM drivers. The C data structures don't compile and in some cases they cause crashes. I do not understand this as the drivers are running and tested and all the data structures are simply ready and need "only" be beautyfied and copied. And in rare cases the processor behaves differently than described (e.g. setting MAINCLKUEN.ENA=0 paralysed the clock - only set MAINCLKUEN.ENA=1).
I hope that a new description will be available soon.

[I]It's a really neat controller and -->exactly what I want.[/I]

Kind regards,
Helmut
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ppx on Mon Jan 28 07:52:58 MST 2013
Is it really worthwhile to use the ROM drivers? What do you gain?  I was thinking abourt trying to port the UART code from from the LPC11XX example. Except for the lack of FIFO, are there any other issues with LPC8XX?
0 Kudos
Reply

3,406 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Helmut Stettmaier on Sat Jan 26 09:28:25 MST 2013
Hello "rw_",
thank you for your response and please excuse the huge delay (so many other ugly things happened).

Quote: "Interestingly, I'm currently working on the same code...." - I hope you were more lucky than I was.

I found some answers:

"1. Is uart_get_char() really blocking?" - Yes, I several times tapped into this trap accidentially, as you did :-)

uart_put_line(...) could be used for non blocking read operations, but I could only use it for one-byte-"lines" as I do not know how long the blocks to be received are and there obviously is no way to stop a line read operation in a "clean" manner before the line buffer is full or an end condition is fulfilled.
The special treatment for blocks, detecting the pause between them, is not covered by the ROM drivers (of course I can't expect this).
uart_put_line(...) may be well suited for building command line processors but not for fishing data from rather "technical" data busses.

"2. How can I watch the serial line until a block of bytes has been received? Blocks in this context are byte sequences separated by pauses..." - I have to employ an MRT channel together with the INTENSET.STARTEN interrupt to detect the idle state. Start the MRT channel in one-shot mode when a start bit is detected and let it run for about 14..16 bit times; as the MRT-channel can be retirggered for each start bit it will not expire as long as an uninterrupted sequence of bytes (= one block) is received.
By the way: The STARTbit event does not fire somewhere during the start bit as the description lets assume but roughly in the middle of the first data bit - as far as I discovered with 38400 Baud.

"3. Does uart_get_mem_size() return a fixed number?" - Yes, 40.

"4. ...I could not find a definition when the RX enters idle mode..." - Asking for the STAT.RXIDLE signal of a UART has no sense as this event cannot fire an interrupt.

A comparison:

[LIST]
[*]ROM drivers need additional 40 Bytes RAM compared to "close to nothing" for direct control.
[/LIST]

[LIST]
[*]ROM drivers  do not use all of the baud rate generation resources (SYSCON-UARTCLKDIV, -UARTFRGDIV and UARTFRGMULT), this is possible under direct control, especially when the 3 baud rates have a common denominator (as usual).
[/LIST]

[LIST]
[*]ROM drivers can't do the whole work as described above.
[/LIST]

[LIST]
[*]Prepare a parameter block and call uart_init(...) to set up the UART compared to writing some values to specific registers (admitted: Finding the correct values is not trivial but filling out the parameter block is easy).     uart_init(...) does not touch the fractional baud rate generator (as far as I discovered) - this results in possibly not really ideal divider values and less accurate baud rates.
[/LIST]

[LIST]
[*]Prepare a parameter block, a callback routine and call uart_put_line(...) in contrast to few lines of code in an interrupt handler for the INTENSET.RXRDYEN event.
[/LIST]

[LIST]
[*]I guess that even the program code for direct control is shorter (in my special case) than the one for calling the ROM drivers.
[/LIST]

All this renders the ROM driver routines unattractive for my special purpose.

Many of the problems during finding out all this were caused by the incomplete, unclear and even buggy description and I do hope that this will improve substantially.

Kind regards,
Helmut
0 Kudos
Reply