ATMega644 port working

Hi folks, I’ve been working on a project using an ATMega640, WinAVR and FreeRTOS for the past few months. I made the following changes to port.c to enable Timer 1 as my OS tick. I’ve also modified the serial port driver to enable the serial ports on this processor. I’ve tried to make it generic but since so far the ATMega640 is the only processor I’ve used it with I don’t know if it’ll work on anything else… Use at your own risk… Hope this proves useful to someone out there. JM in port.c: -————————————————————————————————————– /* Hardware constants for timer 1. */ #define portCLEAR_COUNTER_ON_MATCH                ( ( unsigned portCHAR ) 0x08 ) #define portPRESCALE_64                            ( ( unsigned portCHAR ) 0x03 ) #define portCLOCK_PRESCALER                        ( ( unsigned portLONG ) 64 ) #define portCOMPARE_MATCH_A_INTERRUPT_ENABLE    ( ( unsigned portCHAR ) 0x02 ) /* * Setup timer 1 compare match A to generate a tick interrupt. */ static void prvSetupTimerInterrupt( void ) { unsigned portLONG ulCompareMatch; unsigned portCHAR ucHighByte, ucLowByte;     /* Using 16bit timer 1 to generate the tick.  Correct fuses must be     selected for the configCPU_CLOCK_HZ clock. */     ulCompareMatch = configCPU_CLOCK_HZ / portCLOCK_PRESCALER;     /* calculates the RTOS tick rate based on the timer’s tick rate. */     ulCompareMatch /= configTICK_RATE_HZ;     /* Adjust for correct value. */     ulCompareMatch -= ( unsigned portLONG ) 1;     //ulCompareMatch = (unsigned portLONG) 8639;     /* Setup compare match value for compare match A.  Interrupts are disabled     before this is called so we need not worry here. */     ucLowByte = ( unsigned portCHAR ) ( ulCompareMatch & ( unsigned portLONG ) 0xff );     ulCompareMatch >>= 8;     ucHighByte = ( unsigned portCHAR ) ( ulCompareMatch & ( unsigned portLONG ) 0xff );     OCR1AH = ucHighByte;     OCR1AL = ucLowByte;     /* Setup clock source and compare match behaviour. */     ucLowByte = portCLEAR_COUNTER_ON_MATCH | portPRESCALE_64;     TCCR1B = ucLowByte;     /* Enable the interrupt – this is okay as interrupt are currently globally     disabled. */     ucLowByte = TIMSK1;     ucLowByte |= portCOMPARE_MATCH_A_INTERRUPT_ENABLE;     TIMSK1 = ucLowByte; } -——————————————————————————————————— /* * serial.h * Description: * serial port driver for the ATMega640 */ #ifndef SERIAL_COMMS_H #define SERIAL_COMMS_H typedef enum {     serCOM1,     serCOM2,     serCOM3,     serCOM4,     serCOMPortInvalid } eCOMPort; typedef enum {     serNO_PARITY,     serODD_PARITY,     serEVEN_PARITY,     serMARK_PARITY,     serSPACE_PARITY } eParity; typedef enum {     serSTOP_1,     serSTOP_2 } eStopBits; typedef enum {     serBITS_5,     serBITS_6,     serBITS_7,     serBITS_8,     serBITS_9 } eDataBits; typedef enum {     ser50,            ser75,            ser110,            ser134,            ser150,        ser200,     ser300,            ser600,            ser1200,        ser1800,        ser2400,       ser4800,     ser9600,            ser19200,        ser38400,        ser57600,        ser115200 } eBaud; extern eCOMPort xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength ); extern signed portBASE_TYPE xSerialPutString( eCOMPort ePort, const portCHAR * pcString, portTickType xBlockTime ); extern signed portBASE_TYPE xSerialGetChar( eCOMPort ePort, portCHAR *pcRxedChar, portTickType xBlockTime ); extern signed portBASE_TYPE xSerialPutChar( eCOMPort ePort, portCHAR cOutChar, portTickType xBlockTime ); extern unsigned portBASE_TYPE ubSerialIsActive(eCOMPort ePort); extern void vSerialClose( eCOMPort xPort ); #endif /* * serial.c * Description: * This is a quad serial port driver for ATMega644. * It gives a common interface to open/close serial ports. * $Log: serial.c,v $ * Revision 1.7  2008-05-09 14:23:27+01  jmr * Fixed a memory leak in the serial port driver where allocated memory for the queues wasn’t freed but the pointers to the queues nulled. This meant that if a task opened the same port twice it didn’t get the same queue again…. * The driver now simply will not reallocate a queue when the port is reopened. * */ #include <stdlib.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include "FreeRTOSConfig.h" #include "FreeRTOS.h" #include "queue.h" #include "task.h" #include "serial.h" #define serialMAX_NUM_PORTS 4 #define serialBAUD_DIV_CONSTANT 16 /*———————————————————–*/ static void prvInterruptOn(eCOMPort ePort); static void prvInterruptOff(eCOMPort ePort); /*———————————————————–*/ /* declare some useful constants */ static unsigned portSHORT usBaudRateDivisors[] PROGMEM =                 {                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/50 -1,    //     50                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/75 -1,    //     75                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/110 -1,   //    110                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/134 -1,   //    134                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/150 -1,   //    150                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/200 -1,   //    200                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/300 -1,   //    300                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/600 -1,   //    600                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/1200 -1,  //   1200                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/1800 -1,  //   1800                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/2400 -1,  //   2400                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/4800 -1,  //   4800                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/9600 -1,  //   9600                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/19200 -1, //  19200                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/38400 -1, //  38400                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/57600 -1, //  57600                     configCPU_CLOCK_HZ/serialBAUD_DIV_CONSTANT/115200 -1 // 115200                 }; static unsigned portCHAR ucParityBits[] PROGMEM = { 0x00, /* No parity */                                                      0x30, /* Odd parity */                                                      0x20, /* Even parity */                                                      0x00, /* Mark parity (not supported) */                                                      0x00  /* Space parity (not supported) */                                                   }; static unsigned portCHAR ucDataBits[] PROGMEM = {     0x00, /* 5 data bits */                                                     0x02, /* 6 data bits */                                                     0x04, /* 7 data bits */                                                     0x06, /* 8 data bits */                                                     0x06  /* 9 data bits */                                                 }; /* The Rx And Tx queues used for the serial communications */ static xQueueHandle xRxedChars[serialMAX_NUM_PORTS]; static xQueueHandle xCharsForTx[serialMAX_NUM_PORTS]; /* Serial port initialisation */ eCOMPort xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxQueueLength ) { unsigned portSHORT usBaudRateCounter; unsigned portCHAR ucByte;     /* Verify that the desired port number is supported */     switch( ePort )     {     case serCOM1:     #if serialMAX_NUM_PORTS > 1     case serCOM2:     #endif     #if serialMAX_NUM_PORTS > 2     case serCOM3:     #endif     #if serialMAX_NUM_PORTS > 3     case serCOM4:     #endif         break;     default:         return serCOMPortInvalid;         break;     }     /* Modifying the serial port registers needs to have all interrupts disabled */     portENTER_CRITICAL();     {         /* Create the queues used by the com test task if they weren’t created by a previous call to SerialPortInit         */         if( xRxedChars[ePort] == NULL)         {             xRxedChars[ePort] = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );         }         if( xCharsForTx[ePort] == NULL)         {             xCharsForTx[ePort] = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );         }         /* Calculate the baud rate register value from the equation in the         data sheet. */         //usBaudRateCounter = ( configCPU_CLOCK_HZ / ( serialBAUD_DIV_CONSTANT * ulWantedBaud ) ) – ( unsigned portSHORT ) 1;         usBaudRateCounter = pgm_read_word(&usBaudRateDivisors[eWantedBaud]);         switch( ePort)         {         case serCOM1:             /* Set Parity, data and stop bits */             ucByte = 0;             ucByte |= pgm_read_byte(&ucParityBits[eWantedParity]);             ucByte |= pgm_read_byte(&ucDataBits[eWantedDataBits]);             ucByte |= eWantedStopBits? _BV(USBS0): 0;             UCSR0C = ucByte;             /* Set the baud rate. */                ucByte = ( unsigned portCHAR ) ( usBaudRateCounter & ( unsigned portSHORT ) 0xff );             UBRR0L = ucByte;             usBaudRateCounter >>= ( unsigned portSHORT ) 8;             ucByte = ( unsigned portCHAR ) ( usBaudRateCounter & ( unsigned portSHORT ) 0x0f );                UBRR0H = ucByte;             /* Enable the Rx interrupt.  The Tx interrupt will get enabled             later. Also enable the Rx and Tx. */             UCSR0B = ( _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0) |((eWantedDataBits==serBITS_9)?_BV(UCSZ02):0));             break;         case serCOM2:             /* Set Parity, data and stop bits */             ucByte = 0;             ucByte |= pgm_read_byte(&ucParityBits[eWantedParity]);             ucByte |= pgm_read_byte(&ucDataBits[eWantedDataBits]);             ucByte |= eWantedStopBits? _BV(USBS0): 0;             UCSR1C = ucByte;             /* Set the baud rate. */                ucByte = ( unsigned portCHAR ) ( usBaudRateCounter & ( unsigned portSHORT ) 0xff );             UBRR1L = ucByte;             usBaudRateCounter >>= ( unsigned portSHORT ) 8;             ucByte = ( unsigned portCHAR ) ( usBaudRateCounter & ( unsigned portSHORT ) 0x0f );                UBRR1H = ucByte;             /* Enable the Rx interrupt.  The Tx interrupt will get enabled             later. Also enable the Rx and Tx. */             UCSR1B = ( _BV(RXCIE1) | _BV(RXEN1) | _BV(TXEN1) |((eWantedDataBits==serBITS_9)?_BV(UCSZ12):0) );             break;         case serCOM3:             /* Set Parity, data and stop bits */             ucByte = 0;             ucByte |= pgm_read_byte(&ucParityBits[eWantedParity]);             ucByte |= pgm_read_byte(&ucDataBits[eWantedDataBits]);             ucByte |= eWantedStopBits? _BV(USBS0): 0;             UCSR2C = ucByte;             /* Set the baud rate. */                ucByte = ( unsigned portCHAR ) ( usBaudRateCounter & ( unsigned portSHORT ) 0xff );             UBRR2L = ucByte;             usBaudRateCounter >>= ( unsigned portSHORT ) 8;             ucByte = ( unsigned portCHAR ) ( usBaudRateCounter & ( unsigned portSHORT ) 0x0f );                UBRR2H = ucByte;             /* Enable the Rx interrupt.  The Tx interrupt will get enabled             later. Also enable the Rx and Tx. */             UCSR2B = ( _BV(RXCIE2) | _BV(RXEN2) | _BV(TXEN2) |((eWantedDataBits==serBITS_9)?_BV(UCSZ22):0) );             break;         case serCOM4:             /* Set Parity, data and stop bits */             ucByte = 0;             ucByte |= pgm_read_byte(&ucParityBits[eWantedParity]);             ucByte |= pgm_read_byte(&ucDataBits[eWantedDataBits]);             ucByte |= eWantedStopBits? _BV(USBS0): 0;             UCSR3C = ucByte;             /* Set the baud rate. */                ucByte = ( unsigned portCHAR ) ( usBaudRateCounter & ( unsigned portSHORT ) 0xff );             UBRR3L = ucByte;             usBaudRateCounter >>= ( unsigned portSHORT ) 8;             ucByte = ( unsigned portCHAR ) ( usBaudRateCounter & ( unsigned portSHORT ) 0x0f );                UBRR3H = ucByte;             /* Enable the Rx interrupt.  The Tx interrupt will get enabled             later. Also enable the Rx and Tx. */             UCSR3B = ( _BV(RXCIE3) | _BV(RXEN3) | _BV(TXEN3) |((eWantedDataBits==serBITS_9)?_BV(UCSZ32):0) );             break;         default:             break;         }     }     portEXIT_CRITICAL();         /* Unlike other ports, this serial code does not return a pointer to a port structure        but returns the number of the port opened if successful. Otherwise it returns eCOMPortInvalid.     */     return ePort; } /*———————————————————–*/ /* Get a character from the serial port */ signed portBASE_TYPE xSerialGetChar( eCOMPort ePort, portCHAR *pcRxedChar, portTickType xBlockTime ) {     if( xRxedChars[ePort] == NULL )     {         return pdFAIL;     }     /* Get the next character from the buffer.  Return false if no characters     are available, or arrive before xBlockTime expires. */     if( xQueueReceive( xRxedChars[ePort], pcRxedChar, xBlockTime ) )     {         return pdPASS;     }     else     {         return pdFAIL;     } } /*———————————————————–*/ /* Write a character to the serial port */ signed portBASE_TYPE xSerialPutChar( eCOMPort ePort,portCHAR cOutChar, portTickType xBlockTime ) {     /* ensure the queue has been initialised */     if( xCharsForTx[ePort] == NULL )     {         return pdFAIL;     }         /* Return false if after the block time there is no room on the Tx queue. */     if( xQueueSend( xCharsForTx[ePort], &cOutChar, xBlockTime ) != pdPASS )     {         return pdFAIL;     }     prvInterruptOn(ePort);     return pdPASS; } /* write a NULL terminated string to the serial port */ signed portBASE_TYPE xSerialPutString( eCOMPort ePort, const portCHAR * pcString, portTickType xBlockTime ) { signed portBASE_TYPE retVal = pdPASS;     while(*pcString && (retVal == pdPASS) )     {         retVal = xSerialPutChar( ePort, *pcString++, xBlockTime);     }     return retVal; } unsigned portBASE_TYPE ubSerialIsActive(eCOMPort ePort) {     if(  uxQueueMessagesWaiting(xRxedChars[ePort])        ||uxQueueMessagesWaiting(xCharsForTx[ePort]) )     {         return pdTRUE;     }     else     {         return pdFALSE;     } } /*———————————————————–*/ /* Close the serial port */ void vSerialClose( eCOMPort ePort ) { unsigned portCHAR ucByte;     /* Turn off the interrupt.  We may also want to delete the queues and/or     re-install the original ISR. */     portENTER_CRITICAL();     {         /* turn off the Tx interrupt */         prvInterruptOff(ePort);         /* now turn off the Rx interrupt */         switch( ePort )         {         case serCOM1:             ucByte = UCSR0B;             ucByte &= ~_BV(RXCIE0);             UCSR0B = ucByte;             break;         case serCOM2:             ucByte = UCSR1B;             ucByte &= ~_BV(RXCIE1);             UCSR1B = ucByte;             break;         case serCOM3:             ucByte = UCSR2B;             ucByte &= ~_BV(RXCIE2);             UCSR2B = ucByte;             break;         case serCOM4:             ucByte = UCSR3B;             ucByte &= ~_BV(RXCIE3);             UCSR3B = ucByte;             break;         default:             break;         }         /* invalidate the queue handle */         //xRxedChars[ePort] = NULL;         //xCharsForTx[ePort] = NULL;         // Don’t do the above two lines as this leads to memory leakage on the massive scale!!!     }     portEXIT_CRITICAL(); } /*———————————————————–*/ /* Turn the transmit interrupt ON */ static void prvInterruptOn(eCOMPort ePort) {     unsigned portCHAR ucByte;     switch( ePort )     {     case serCOM1:         ucByte = UCSR0B;         ucByte |= _BV(UDRIE0);         UCSR0B = ucByte;         break;     case serCOM2:         ucByte = UCSR1B;         ucByte |= _BV(UDRIE0);         UCSR1B = ucByte;         break;     case serCOM3:         ucByte = UCSR2B;         ucByte |= _BV(UDRIE0);         UCSR2B = ucByte;         break;     case serCOM4:         ucByte = UCSR3B;         ucByte |= _BV(UDRIE0);         UCSR3B = ucByte;         break;     default:         break;     } }                                                                                /* Turn the transmit interrupt OFF */ static void prvInterruptOff(eCOMPort ePort) {     unsigned portCHAR ucByte;     switch( ePort )     {     case serCOM1:         ucByte = UCSR0B;         ucByte &= ~_BV(UDRIE0);         UCSR0B = ucByte;         break;     case serCOM2:         ucByte = UCSR1B;         ucByte &= ~_BV(UDRIE0);         UCSR1B = ucByte;         break;     case serCOM3:         ucByte = UCSR2B;         ucByte &= ~_BV(UDRIE0);         UCSR2B = ucByte;         break;     case serCOM4:         ucByte = UCSR3B;         ucByte &= ~_BV(UDRIE0);         UCSR3B = ucByte;         break;     default:         break;     } } /*———————————————————–*/ /************************************************************* * Interrupt handlers below *************************************************************/ /* * serial port 1 Rx and Tx interrupt handlers */ ISR( USART0_RX_vect ) { portCHAR cChar; portBASE_TYPE bResVal;     /* Get the character and post it on the queue of Rxed characters.     If the post causes a task to wake force a context switch as the woken task     may have a higher priority than the task we have interrupted. */     cChar = UDR0;         portENTER_CRITICAL();     bResVal = xQueueSendFromISR( xRxedChars[0], &cChar, pdFALSE );     portEXIT_CRITICAL();     if( bResVal == pdTRUE )     {         taskYIELD();     } } /*———————————————————–*/ ISR( USART0_UDRE_vect ) { portCHAR cChar; signed portCHAR cTaskWoken; portBASE_TYPE bResVal;     portENTER_CRITICAL();     bResVal = xQueueReceiveFromISR( xCharsForTx[0], &cChar, &cTaskWoken );     portEXIT_CRITICAL();     if(  bResVal == pdTRUE )     {         /* Send the next character queued for Tx. */         UDR0 = cChar;     }     else     {         /* Queue empty, nothing to send. */         prvInterruptOff(serCOM1);     } } /* * serial port 2 Rx and Tx interrupt handlers */ ISR( USART1_RX_vect ) { portCHAR cChar;     /* Get the character and post it on the queue of Rxed characters.     If the post causes a task to wake force a context switch as the woken task     may have a higher priority than the task we have interrupted. */     cChar = UDR1;     if( xQueueSendFromISR( xRxedChars[1], &cChar, pdFALSE ) )     {         taskYIELD();     } } /*———————————————————–*/ ISR( USART1_UDRE_vect ) { portCHAR cChar; signed portCHAR cTaskWoken;     if( xQueueReceiveFromISR( xCharsForTx[1], &cChar, &cTaskWoken ) == pdTRUE )     {         /* Send the next character queued for Tx. */         UDR1 = cChar;     }     else     {         /* Queue empty, nothing to send. */         prvInterruptOff(serCOM2);     } } /* * serial port 3 Rx and Tx interrupt handlers */ ISR( USART2_RX_vect ) { portCHAR cChar;     /* Get the character and post it on the queue of Rxed characters.     If the post causes a task to wake force a context switch as the woken task     may have a higher priority than the task we have interrupted. */     cChar = UDR2;     if( xQueueSendFromISR( xRxedChars[2], &cChar, pdFALSE ) )     {         taskYIELD();     } } /*———————————————————–*/ ISR( USART2_UDRE_vect ) { portCHAR cChar; signed portCHAR cTaskWoken;     if( xQueueReceiveFromISR( xCharsForTx[2], &cChar, &cTaskWoken ) == pdTRUE )     {         /* Send the next character queued for Tx. */         UDR2 = cChar;     }     else     {         /* Queue empty, nothing to send. */         prvInterruptOff(serCOM3);     } } /* * serial port 4 Rx and Tx interrupt handlers */ ISR( USART3_RX_vect ) { portCHAR cChar;     /* Get the character and post it on the queue of Rxed characters.     If the post causes a task to wake force a context switch as the woken task     may have a higher priority than the task we have interrupted. */     cChar = UDR3;     if( xQueueSendFromISR( xRxedChars[3], &cChar, pdFALSE ) )     {         taskYIELD();     } } /*———————————————————–*/ ISR( USART3_UDRE_vect ) { portCHAR cChar; signed portCHAR cTaskWoken;     if( xQueueReceiveFromISR( xCharsForTx[3], &cChar, &cTaskWoken ) == pdTRUE )     {         /* Send the next character queued for Tx. */         UDR3 = cChar;     }     else     {         /* Queue empty, nothing to send. */         prvInterruptOff(serCOM4);     } }

ATMega644 port working

Thanks for taking the time to post this up. Regards.

ATMega644 port working

nice.. i have hacked a single usart version for the ATMega2560 myself.. One thing, though.. i think you should write UBBRH *before* writing UBBRL, since writing UBBRL triggers an update of the baud rate prescaler, whereas writing UBBRH does not.. This mistake is present in the ATMega323 port as well, by the way…

ATMega644 port working

I’ll have to check this one out as this code hasn’t been a problem for the past few months that it has been running. Granted I only have 3 baudrates that I’ve tested (4800, 9600 and 115200) but you never know. I seem to remember trying the datasheet way and not getting what I expected. Then again it could have been from other bug sources so… If I get a few minutes I’ll swap the lines around and check.

ATMega644 port working

I am using your port mostly as is on an ATMega2560 @ 14.7MHz. When receiving data on USART0 at 115200 baud, the received bytes, but the first one, are wrong. if i transmit manually, all bytes are ok. this is not just an issue about missed bytes, since the received bit patterns were never transmitted, so somehow, bytes transmitted closely spaced, are not received correctly (only the first one after a timeout). what is strange is, switching to USART1 makes it all work.. i was thinking of something like interrupt priorities, but that couldn’t cause bytes to be received that were never sent… there’s only the receiver task running.. any ideas?

ATMega644 port working

Is this thread of any help: https://sourceforge.net/forum/forum.php?thread_id=2052807&forum_id=382005

ATMega644 port working

not really.. i know that i shouldn’t post a byte at a time to the queue in the optimal solution, but the hardware has no fifo or dma, so… anyway, so far, i’m only doing testing, and it’s really strange that it works for usart1, but not for usart0… also, shouldn’t the xQueueSendFromISR’s above use the version with pointers for argument 3? i didn’t discover that here at first, but it doesn’t seem to make any difference on application behavior.. regards…

ATMega644 port working

Are you using the code I posted to start this thread? Unfortunately I can’t check the 115200 on USART0 as on my board this is connected to a device that only works at 19200. It does seem strange indeed that it works for USART1 but not USART0. You might want to try swapping the initialisation order of UBBR0L and UBBR0H if you’re the code of this thread.

ATMega644 port working

i am using your serial.c with slight modifications (init UBRRH before UBRRL, made the USART_RX_vect routines look the same (usart0 was different), changed some register bit names to the correct usart number,  updated the xQueueSendFromISR calls to be FreeRTOS 5 compatible, etc). i’ve made sure, that the code in serial.c is similar for all 4 USART’s, so unless i missed something, that’s not it… if this was a baud rate problem, the characters sent manually from a simple terminal proggy would arrive wrong, so this is not the issue.. regards…

ATMega644 port working

Actually looking at my code a bit more, there are a few blushes I could have saved myself. I think I was tinkering with getting things working on my board at the time and forgot to update the "driver" once I got things to work for me. Note to self: don’t forget to update the rest of your driver before moving onto the next task. As for your issue this is very puzzling. If with exactly the same code it works on USART1 but not USART0 I would start questioning the MCU itself. I suppose you have tried setting a breakpoint in the ISR to check that this got fired as soon as transmission was started. I might be able to do a wire mod to my PCB and swap USART0 and USART1 to check the behaviour there… However looking at the data-sheet I don’t think that this would help you as it seems that even though the 640 is the smaller flash size version of the 2560 they have different errata… Did you try a minimal set of code to send to the Atmel support guys? They are quite helpful, providing you’ve minimised the code. What I’d do is replace the calls to FreeRTOS API by a simple write to a byte array and see if the USART0 still looses the first byte of data. If not then there’s a bad interaction with FreeRTOS.

ATMega644 port working

JMR, I think you misunderstood me, or i expressed myself poorly. I am *not* missing the first byte on any USART, but on USART0, the byte *after* the first one is somehow scrambled when the bytes are closely spaced. If I transmit manually using a terminal program (typing one character at a time), bytes get received correctly. this led me to believe it was task switching related, but it can’t be, since it works for USART1 and the tick timer uses a higher priority ISR than both USARTs. Also, the baud rate has to be correct, since i can receive correct characters. cheers.