Read and write to rs232 from C code (RLPLight) over Hydra


I saw this guid and code:

but it doesnt work at all…

i did the following:

in C#: (i am using rs232 on socket 7)

var COM2 = new SerialPort("COM2", 57600, System.IO.Ports.Parity.None, 8, StopBits.One);

i see it works from C#. then i call to RLPLight and try to send data to this serial like the example in the link above, with this function:

void Debug_print_UCHR(unsigned char c)
  U1THR = c;
while (!(U1LSR & LSR_TEMT));


 #define UART1_BASE_ADDR        0xE0010000 //COM1 = 0xE000C000; COM2 = 0xE0010000; COM3 = 0xE0078000
 #define U1THR  (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x00))
 #define U1LSR  (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x14))
 #define LSR_TEMT    0x40 

in the bottom line it doesnt work at all (looks like infinit loop…)

The addresses you have used is probably for th EMX which uses a different CPU.

I would suggest that you use the header files for the target CPU when doing RLP. It will save you the hassle of defining the structures and addresses.

I use very similar code to this when writing RLP code for debugging, here is the function I have

void debug_print(char *str)
  char *p = str;
  while (*p != 0)
    AT91C_BASE_US0->US_THR = *p++;
    while ((AT91C_BASE_US0->US_CSR & 2) == 0) ;

This will write to COM2 as defined in your code on the Hydra.

The structures are defined in AT91SAM9RL64.h


i see in the header file few defines:

 #define AT91C_BASE_PDC_US0   (AT91_CAST(AT91PS_PDC) 	0xFFFB0100) // (PDC_US0) Base Address
 #define AT91C_BASE_US0       (AT91_CAST(AT91PS_USART) 	0xFFFB0000) // (US0) Base Address
 #define AT91C_BASE_PDC_US1   (AT91_CAST(AT91PS_PDC) 	0xFFFB4100) // (PDC_US1) Base Address
 #define AT91C_BASE_US1       (AT91_CAST(AT91PS_USART) 	0xFFFB4000) // (US1) Base Address
 #define AT91C_BASE_PDC_US2   (AT91_CAST(AT91PS_PDC) 	0xFFFB8100) // (PDC_US2) Base Address
 #define AT91C_BASE_US2       (AT91_CAST(AT91PS_USART) 	0xFFFB8000) // (US2) Base Address
 #define AT91C_BASE_PDC_US3   (AT91_CAST(AT91PS_PDC) 	0xFFFBC100) // (PDC_US3) Base Address
 #define AT91C_BASE_US3       (AT91_CAST(AT91PS_USART) 	0xFFFBC000) // (US3) Base Address

how can i know which of them to use? does US0 is like COM0, US1 like COM1 and so…
which of them to use? and does it matter which socket i use on Hydra board?

@ shm3 - Well, that is the fun part :slight_smile:

What I did was look at the schematic for the Hydra to determine which CPU UART pins are connected to which Gadgeteer Socket on the Hydra board. From that I could determine the AT91C_BASE_US0 maps to NETMF COM2.


Afetr your explanations, i choosed the easy way (google) :slight_smile:

found this:

For non-gadgeteer applications the COM ports are as follows:

COM1 = Socket 5 -->> On Schematic it is DTXD\DRXD

COM2 = Socket 7 -->> On Schematic it is TXD0\RXD0

COM3 = Socket 4 -->> On Schematic it is TXD1\RXD1

COM4 = Socket 6 -->> On Schematic it is TXD2\RXD2

Taylorza thanks! it works!

before i mark it as “solved” - how can i read in RLP (in your example read from COM2)?

To write to the port you put a byte into the Transmitter Holding Register (US_THR), to read you read from the Receiver Holding Register (US_RHR). Of course you should first check that there is data to be read, bit 0 of the US_CSR register indicates that there is data available in the RHR.

Here is the data sheet for the AT91SAM9RL64 mcu used in the Hydra, this is the go to document if you want understand how to effectively work with the peripherals offered by this mcu.

thanks a lot taylorza!!

i tried it (reading from RLP to serial) but it doesnt work…

my code:

char* Serial_read()
       char p[10];
       char *p1;
       p1 = &p[0];
       while ((AT91C_BASE_US0->US_CSR & 1) != 0)
             *p1++ = AT91C_BASE_US0->US_RHR ;
        return p1;

@ shm3 - There are a few issues with this code.

[ol]You are returning a pointer to the local variable ‘p’. Once the function returns the stack space used for the locals is reclaimed and will get clobbered by any subsequent function calls.
The code will have to be lucky to get called at the right time to detect the presence of a character in the buffer
If you do start reading characters you have nothing to prevent you from overwriting the ‘p’ buffer[/ol]

For the first issue I would suggest that you pass the buffer in to the function and also pass the length of the buffer and have the function return the number of bytes read. You can use that length to limit the reads, this will help address point 3 above as well.

int Serial_Read(char *pBuffer, int size) ...

For the second issue, you probably want to loop until the flag indicates there is a character in the holding register then you will fall out of the loop and read the character from the register. To ensure that you do not loop forever, you can limit the number of times the loop will run before giving up and returning 0 bytes read.

@ taylorza - Here is a quick and dirty example, I tested this and it works.

First you need to disable the receive ready interrupt, otherwise .NET will steal the characters from you.

// Disable the receiver interrupt
AT91C_BASE_US0->US_IDR = 0x01;

// Enable the receiver, this is probably not required. I just put it in and did not test without it.
AT91C_BASE_US0->US_CR = 0x10; 

Then your code to read from the port, here is a very quick and dirty implementation. It does not timeout it reads up to ‘size’ bytes before returning.

int read_serial(char *pBuffer, int size)
  int bytesRead = 0;
  while ((size - bytesRead) > 0)
    // Wait for a character to arrive
    while ((AT91C_BASE_US0->US_CSR & 1) == 0) ;
    // Add the character to the buffer    
    *pBuffer++ = (char)AT91C_BASE_US0->US_RHR;
  return bytesRead;

To call the above function, you can do the following

char buffer[10];
int read = read_serial(buffer, 5);
if (read > 0)
  buffer[read] = '\0';

This code creates a buffer of 10 chars. Then waits to read 5 character, these are just arbitrary numbers I chose for demonstration purposes, and then echos them back over the serial port.

Note 1: We are doing some nasty things here, so the .NET serial class will most likely stop working on the managed side. But you can send and receive on the native side.

Note 2: You will definitely want to implement the timeout so that you do not block for ever on the read if you do not get any or enough data to match the size passed to the read_serial function.

1 Like

@ taylorza - Talking to yourself? :wink:

The first sign of madness :slight_smile:

or brilliance

@ Mike - good point!


I nearly fell off my chair laughing, that was a good one!!!

@ Mike - Good one! :smiley: Reminded me of Golum.

@ Architect - don’t forget to plus 1 Mike’s post.

@ Precious - these little Hobbitses are cracking us up this morning.


Thanks a lot!

i used your code and added timeout:

int read_serial(char *pBuffer, int size, int timeout)
  int bytesRead = 0;
  while (((size - bytesRead) > 0) && (timeout >= 0) )
    // Wait for a character to arrive
    while ( (timeout >= 0) && ((AT91C_BASE_US0->US_CSR & 1) == 0))
    // Add the character to the buffer    
    *pBuffer++ = (char)AT91C_BASE_US0->US_RHR;
  return bytesRead;

I am using this function with timeout = 0 and try to read 1 char in loop. The problem is that i think the buffer (AT91C_BASE_US0->US_RHR) doesn’t clear and i read this byte each time i try to read. (unless i write other byte…)
my code look like:

while (true)
                      //do some work..
	read_serial(&reciveBuffer[0],1, 0);
	//check if got stop command
	if (reciveBuffer[0] == STOP_VALUE)
	       //do sonething

i see that after i sent STOP_VALUE over serial code always insert to this “if”…

maybe i need to “clear” receiver after i read from??

@ shm3 - It is a pleasure!

One thing that I see, is that after your timeout expires you are reading the US_RHR register, but I would assume that you timed-out because no character has arrived and therefore reading the register is undefined.

I see its your bread & butter… :slight_smile:

i will try later…

I asked more question about RLP and butten pressed event. Are you fimilar also with that? you can see it here :