USART_ID usartOpen(USART_ID usartId, uint32_t ulWantedBaud, uint16_t uxTxQueueLength, uint16_t uxRxQueueLength ) { uint8_t * dataPtr; /* Create the ring-buffers for the USART. */ if( (dataPtr = (uint8_t *)pvPortMalloc( sizeof(uint8_t) * uxRxQueueLength ))) ringBuffer_InitBuffer( &(usartComBuf[usartId].xRxedChars), dataPtr, uxRxQueueLength); if( (dataPtr = (uint8_t *)pvPortMalloc( sizeof(uint8_t) * uxTxQueueLength ))) ringBuffer_InitBuffer( &(usartComBuf[usartId].xCharsForTx), dataPtr, uxTxQueueLength); // create a working buffer for vsnprintf on the heap (so we can use extended RAM, if available). // create the structures on the heap (so they can be moved later). if( !(usartComBuf[usartId].workBuffer = (uint8_t *)pvPortMalloc( sizeof(uint8_t) * uxTxQueueLength ))) usartComBuf[usartId].workBuffer = NULL; usartComBuf[usartId].workBufferSize = uxTxQueueLength; // size of the working buffer for vsnprintf usartComBuf[usartId].workBufferInUse = USART_VACANT; // clear the occupation flag. portENTER_CRITICAL(); // Disable interrupts during configuration /* * Calculate the baud rate register value from the equation in the data sheet. */ /* As the 16MHz Arduino boards have bad karma for serial port, we're using the 2x clock U2X0 */ // for Arduino at 16MHz; above data sheet calculation is wrong. Need below from <util/setbaud.h> // This provides correct rounding truncation to get closest to correct speed. // Normal mode gives 3.7% error, which is too much. Use 2x mode gives 2.1% error. // Or, use 22.1184 MHz over clock which gives 0.00% error, for all rates. // ulBaudRateCounter = ((configCPU_CLOCK_HZ + ulWantedBaud * 8UL) / (ulWantedBaud * 16UL) - 1); // for normal mode // ulBaudRateCounter = (uint16_t)((configCPU_CLOCK_HZ + ulWantedBaud * 4UL) / (ulWantedBaud * 8UL) - 1); // for 2x mode *usartReg[usartId].ubbrPtr = (uint16_t)((configCPU_CLOCK_HZ + ulWantedBaud * 4UL) / (ulWantedBaud * 8UL) - 1); // for 2x mode, using 16 bit avr-gcc capability. /* Set the 2x speed mode bit */ *usartReg[usartId].ucsrAPtr = U2X_BIT; /* bits 7:2 are status bits, bit 0 set to 0 disables multi-processor comms mode */ /* Enable the Rx and Tx. Also enable the Rx interrupt. The Tx interrupt will get enabled later. */ *usartReg[usartId].ucsrBPtr = RXCIE_BIT | RXEN_BIT | TXEN_BIT; /* Set the data bit register to 8n1. */ /* Set to asycrhnoous USART (bits 7:6 set to 0), parity disables (bits 5:4 is 0) 1 stop bit (bit 3 set to 0) * 8 data bits (UCSZ1, UCSZ0 set to 1) */ *usartReg[usartId].ucsrCPtr = UCSZ1_BIT | UCSZ0_BIT; // 011 stored in UCSZ2:1 - bit UCSZ2 is zero in register ucsrB (above instruction) portEXIT_CRITICAL(); // Enables interrupts after configuration return usartId; }
xComPortHandle xSerialPortInitMinimal( eCOMPort ePort, uint32_t ulWantedBaud, uint16_t uxTxQueueLength, uint16_t uxRxQueueLength ) { uint8_t * dataPtr; xComPortHandle newComPort; /* Create the ring-buffers used by the serial communications task. */ if( (dataPtr = (uint8_t *)pvPortMalloc( sizeof(uint8_t) * uxRxQueueLength ))) ringBuffer_InitBuffer( &(newComPort.xRxedChars), dataPtr, uxRxQueueLength); if( (dataPtr = (uint8_t *)pvPortMalloc( sizeof(uint8_t) * uxTxQueueLength ))) ringBuffer_InitBuffer( &(newComPort.xCharsForTx), dataPtr, uxTxQueueLength); // create a working buffer for vsnprintf on the heap (so we can use extended RAM, if available). // create the structures on the heap (so they can be moved later). if( !(newComPort.serialWorkBuffer = (uint8_t *)pvPortMalloc( sizeof(uint8_t) * uxTxQueueLength ))) newComPort.serialWorkBuffer = NULL; newComPort.usart = ePort; // containing eCOMPort newComPort.serialWorkBufferSize = uxTxQueueLength; // size of the working buffer for vsnprintf newComPort.serialWorkBufferInUse = VACANT; // clear the occupation flag. portENTER_CRITICAL(); switch (newComPort.usart) { case USART0: /* * Calculate the baud rate register value from the equation in the data sheet. */ /* As the 16MHz Arduino boards have bad karma for serial port, we're using the 2x clock U2X0 */ // for Arduino at 16MHz; above data sheet calculation is wrong. Need below from <util/setbaud.h> // This provides correct rounding truncation to get closest to correct speed. // Normal mode gives 3.7% error, which is too much. Use 2x mode gives 2.1% error. // Or, use 22.1184 MHz over clock which gives 0.00% error, for all rates. // ulBaudRateCounter = ((configCPU_CLOCK_HZ + ulWantedBaud * 8UL) / (ulWantedBaud * 16UL) - 1); // for normal mode // ulBaudRateCounter = (uint16_t)((configCPU_CLOCK_HZ + ulWantedBaud * 4UL) / (ulWantedBaud * 8UL) - 1); // for 2x mode UBRR0 = (uint16_t)((configCPU_CLOCK_HZ + ulWantedBaud * 4UL) / (ulWantedBaud * 8UL) - 1); // for 2x mode, using 16 bit avr-gcc capability. /* Set the 2x speed mode bit */ UCSR0A = _BV(U2X0); /* Enable the Rx and Tx. Also enable the Rx interrupt. The Tx interrupt will get enabled later. */ UCSR0B = ( _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0)); /* Set the data bit register to 8n1. */ UCSR0C = ( _BV(UCSZ01) | _BV(UCSZ00) ); break; case USART1: #if defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__)|| defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega644PA__) ||defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) UBRR1 = (uint16_t)((configCPU_CLOCK_HZ + ulWantedBaud * 4UL) / (ulWantedBaud * 8UL) - 1); UCSR1A = _BV(U2X1); UCSR1B = ( _BV(RXCIE1) | _BV(RXEN1) | _BV(TXEN1)); UCSR1C = ( _BV(UCSZ11) | _BV(UCSZ10) ); break; #endif case USART2: case USART3: default: break; } portEXIT_CRITICAL(); return newComPort; }