I’m trying to design a application for my arm7 that’ll wait for data to start coming in from UART0 and then start processing it.
I’m able to determin the exact number of bytes I’m expecting to receive by reading the first 3 bytes that I receive as the 3rd byte dictates the whole number of bytes expected.
What I want to achieve here is basically have call a routine after the first 3 bytes have been received and then read the 3rd byte and store it in a value then call another routine to grab the rest of the bytes expected and then depending on what was received respond back with a proper formated response.
Any clues or example code I can look at.
I’ve already gotten uart0 working to send data from my arm7 to my pc with some sample code I downloaded but haven’t been able to get more then one char at a time.
Ok I have that code already in this demo that I’m trying to use to make my app from.
What I don’t understand is how to use it to get the 3rd byte and then from that 3rd byte determin number of bytes left to read from buffer then once all bytes read clear rx buffer and wait again…
Just put everything into into the circular buffer. If it’s ASCII you can use control codes to identify the start and finish of the block of data. I send fixed length records with CRC, which makes things easy. I also use a simple ACK/NAK protocol between the two systems.
I’ve done vb.net and asp.net and php code but never have I done c/c++ code nor have I ever worked with micro devices.
This is 100% new to me so I haven’t a clue on what a circular buffer is.
All I know is the sample demo code I grabbed works perfectly for sending data strings to the pc but I’ve yet to figure a way to get strings of data sent from the pc to the uart to then be re-echoed back to the pc to show that it was infact received.
Sorry if me being a totall newbie at this hinders your ability to help me.
Try Google. Most comms systems use circular buffers.
You don’t need to echo the data back if you use CRC and a simple protocol like the one I mentioned. I’m actually using it for sending commands from a PC to an LPC2148 system, and sending data back from the LPC2148 to the PC. This is how I implemented it on the LPC2148:
unsigned int get_command()
{
u_long crc, received_crc; // crc is the calculated CRC
unsigned char temp1[20], temp2[20];
unsigned char temp[10];
if (serial_buffer_ptr == 12) // if all 12 characters have been received
{
(void) strncpy(temp1, serial_buffer, 4); // get command in temp1
temp1[4] = 0; // terminating null for string
(void) strncpy(temp2, serial_buffer+4, 8); // get CRC in temp2
temp2[8] = 0; // terminating null for string
sscanf(temp2, "%8lx", &received_crc); // convert received CRC string to a long
crc = crc32(temp1, 4); // calculate CRC for command string
{
if (crc == received_crc) // compare received and calculated CRCs
{
serout0(ACK); // send ACK if they match
serout0(CR);
serout0(LF);
#ifndef NDEBUG
debug_puts("ACK");
#endif
serial_buffer_ptr = 0; // reset pointer
if (temp1[0] == '3') //test for Ekta Asssembly
{
if (temp1[1] == '5')
{
temp[0] = temp1[2];//extract 2 hex digits into temp (string)
temp[1] = temp1[3];
temp[2] = '\0';
sscanf(temp, "%X", &speed);//convert string to decimal in speed
return(35);
}
}
else
return(atoi(temp1)); // return command as numeric value
}
else
{
serout0(NAK); // send NAK if they don't match
serout0(CR);
serout0(LF);
#ifndef NDEBUG
debug_puts("NAK");
#endif
serial_buffer_ptr = 0; // reset pointer
return(0);
}
}
}
else
return(0);
}
I get the data from the circular buffer, check the CRC and send an ACK if it is correct, or a NAK if there is an error. The PC does the same thing with the received data. We never get any errors, but we need to check as it’s a medical system and the consequences of the wrong data being received could be disastrous for the patient.
Ok here’s what I’ve got so far but can’t seem to get it working.
Routine to extract a certain number of bytes and return them in a string.
int uart0Gets(int bytes)
{
uint8_t data;
int count = 1;
if (uart0_rx_insert_idx == uart0_rx_extract_idx) // check if character is available
return -1;
while (count <= bytes)
{
data += uart0_rx_buffer[uart0_rx_extract_idx++]; // get character, bump pointer
uart0_rx_extract_idx %= UART0_RX_BUFFER_SIZE; // limit the pointer
count +=1;
}
return data;
}
Routine called by some code
for (;;) {
if ((ch = uart0Gets(1)) >= 1)
{
uart0Puts("Bytes Received\r\n");
}
}
return 0;
echel0n:
Ok here’s my new function for grabbing a specified number of bytes from uart0
char rx_data[30];
char uart0GetBytes(int bytes)
{
int rx_size = 0;
do {
} while (uart0_rx_insert_idx == uart0_rx_extract_idx);
uart0Puts("1\r\n");
while (rx_size != bytes - 1) {
rx_data[rx_size++] = uart0_rx_buffer[uart0_rx_extract_idx++];
}
uart0Puts("2\r\n");
uart0_rx_extract_idx %= UART0_RX_BUFFER_SIZE;
rx_size = 0;
uart0Puts("3\r\n");
return *rx_data;
}
It doesn't seem to work, I type in 3 bytes via hyperterminal and it never displays them. Actually for that matter it never even prints number 1.
My quick read:
Logic design error?
the first while loop waits for one or more bytes to be in the buffer.
the second while loop takes one byte but does not preclude a buffer-is-empty situation in the loop. if the passed variable “bytes” is > 1. This can work if enough bytes have already arrived before the function is called.
Also: incrementing the buffer pointers (all cases, including the interrupt routine), need to do the end of buffer wrap after every increment and that code as is doesn’t. It’s a good idea to make the buffer size a power of 2 and use a bitwise AND rather than a modulo operator, though some compilers will in effect do so anyway.
new code is left as an exercise for the student, as they say.
How are you debugging your software? You should be able to check if the interrupt is being called and trace through the program to see where it is going wrong.
Ok it’s this line that seems to be were i’m getting hung up on in the code.
do {
} while (uart0_rx_insert_idx == uart0_rx_extract_idx);
The way you call this routine is by doing this:
nRet = GetBytes(3);
When you start up the devel board with this code and go into a terminal window it just looks like it’s stuck but if you hit reset well holding down a key on the keyboard it’ll display that key and go through.
Ok i’ve made some more changes to the routine but still it doesn’t seem to be working, seems to me it’s stuck in the loop and never has a chance to get the bytes I’m wanting.
char uart0GetBytes(int bytes)
{
int rx_size = 0;
int ch;
while (rx_size != bytes - 1) {
if ((ch = uart0Getch()) >= 0) {
rx_data[rx_size++] = ch;
}
}
uart0Puts("2\r\n");
rx_size = 0;
return *rx_data;
}
Ok I’ve solved one problem and this new code seems to work as long as I have interrupts disabled. Would it be better to use interrupts ?
Getbytes function
char* uart0GetBytes(void)
{
static char rx_data[256];
int rx_size = 0;
int bytes = 3;
int ch;
do {
if ((ch = uart0Getch()) >= 0) {
rx_data[rx_size++] = ch;
}
} while (rx_size != (bytes * 2));
return rx_data;
}
RX ISR Interrupt function
void uart0ISR(void)
{
uint8_t iid;
// perform proper ISR entry so thumb-interwork works properly
ISR_ENTRY();
// loop until not more interrupt sources
while (((iid = U0IIR) & UIIR_NO_INT) == 0)
{
// identify & process the highest priority interrupt
switch (iid & UIIR_ID_MASK)
{
case UIIR_RLS_INT: // Receive Line Status
U0LSR; // read LSR to clear
break;
#ifdef UART0_RX_INT_MODE
case UIIR_CTI_INT: // Character Timeout Indicator
case UIIR_RDA_INT: // Receive Data Available
do
{
uint16_t temp;
// calc next insert index & store character
temp = (uart0_rx_insert_idx + 1) % UART0_RX_BUFFER_SIZE;
uart0_rx_buffer[uart0_rx_insert_idx] = U0RBR;
// check for more room in queue
if (temp != uart0_rx_extract_idx)
uart0_rx_insert_idx = temp; // update insert index
}
while (U0LSR & ULSR_RDR);
LED1_PIN ^= LED1_BIT;
break;
#endif
#ifdef UART0_TX_INT_MODE
case UIIR_THRE_INT: // Transmit Holding Register Empty
while (U0LSR & ULSR_THRE)
{
// check if more data to send
if (uart0_tx_insert_idx != uart0_tx_extract_idx)
{
U0THR = uart0_tx_buffer[uart0_tx_extract_idx++];
uart0_tx_extract_idx %= UART0_TX_BUFFER_SIZE;
}
else
{
// no
uart0_tx_running = 0; // clear running flag
break;
}
}
break;
#endif // UART0_TX_INT_MODE
default: // Unknown
U0LSR;
U0RBR;
break;
}
}
VICVectAddr = 0x00000000; // clear this interrupt from the VIC
ISR_EXIT(); // recover registers and return
}