Index: webserver/example/EnergyMeters/Source/serial.c =================================================================== --- webserver/example/EnergyMeters/Source/serial.c (revision 37) +++ webserver/example/EnergyMeters/Source/serial.c (revision 37) @@ -0,0 +1,381 @@ +/* + FreeRTOS.org V5.0.2 - Copyright (C) 2003-2008 Richard Barry. + + This file is part of the FreeRTOS.org distribution. + + FreeRTOS.org is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + FreeRTOS.org is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FreeRTOS.org; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes FreeRTOS.org, without being obliged to provide + the source code for any proprietary components. See the licensing section + of http://www.FreeRTOS.org for full details of how and when the exception + can be applied. + + *************************************************************************** + *************************************************************************** + * * + * SAVE TIME AND MONEY! We can port FreeRTOS.org to your own hardware, * + * and even write all or part of your application on your behalf. * + * See http://www.OpenRTOS.com for details of the services we provide to * + * expedite your project. * + * * + *************************************************************************** + *************************************************************************** + + Please ensure to read the configuration and relevant port sections of the + online documentation. + + http://www.FreeRTOS.org - Documentation, latest information, license and + contact details. + + http://www.SafeRTOS.com - A version that is certified for use in safety + critical systems. + + http://www.OpenRTOS.com - Commercial support, development, porting, + licensing and training services. +*/ + + +/* + BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART0. +*/ + +/* Standard includes. */ +#include + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "queue.h" +#include "task.h" + +#include "semphr.h" + +/* Demo application includes. */ +#include "serial.h" + + +/*-----------------------------------------------------------*/ + +/* Constants to setup and access the UART. */ +#define serDLAB ( ( unsigned portCHAR ) 0x80 ) +#define serENABLE_INTERRUPTS ( ( unsigned portCHAR ) 0x03 ) +#define serNO_PARITY ( ( unsigned portCHAR ) 0x00 ) +#define ser1_STOP_BIT ( ( unsigned portCHAR ) 0x00 ) +#define ser8_BIT_CHARS ( ( unsigned portCHAR ) 0x03 ) +#define serFIFO_ON ( ( unsigned portCHAR ) 0x01 ) +#define serCLEAR_FIFO ( ( unsigned portCHAR ) 0x06 ) +#define serWANTED_CLOCK_SCALING ( ( unsigned portLONG ) 16 ) + +/* Constants to setup and access the VIC. */ +#define serU3VIC_CHANNEL ( ( unsigned portLONG ) 0x0006 ) +#define serU3VIC_CHANNEL_BIT ( ( unsigned portLONG ) 0x0040 ) +#define serU3VIC_ENABLE ( ( unsigned portLONG ) 0x0020 ) +#define serCLEAR_VIC_INTERRUPT ( ( unsigned portLONG ) 0 ) + +/* Constants to determine the ISR source. */ +#define serSOURCE_THRE ( ( unsigned portCHAR ) 0x02 ) +#define serSOURCE_RX_TIMEOUT ( ( unsigned portCHAR ) 0x0c ) +#define serSOURCE_ERROR ( ( unsigned portCHAR ) 0x06 ) +#define serSOURCE_RX ( ( unsigned portCHAR ) 0x04 ) +#define serINTERRUPT_SOURCE_MASK ( ( unsigned portCHAR ) 0x0f ) + +/* Misc. */ +#define serINVALID_QUEUE ( ( xQueueHandle ) 0 ) +#define serHANDLE ( ( xComPortHandle ) 1 ) +#define serNO_BLOCK ( ( portTickType ) 0 ) + +/*-----------------------------------------------------------*/ + +/* Queues used to hold received characters, and characters waiting to be +transmitted. */ +static xQueueHandle xRxedChars; +static xQueueHandle xCharsForTx; +static volatile portLONG lTHREEmpty = pdFALSE; + +/*-----------------------------------------------------------*/ + +/* The ISR. Note that this is called by a wrapper written in the file +SerialISR.s79. See the WEB documentation for this port for further +information. */ +void vSerialISR( void ); + + +extern void ( vUART3_ISR_Wrapper )( void ); +extern unsigned int uart3TxRunning; + + + + +/* The interrupt entry point. */ +void vUART3_ISR_Wrapper( void ) __attribute__((naked)); + +/* The function that actually performs the interrupt processing. This must be +separate to the wrapper to ensure the correct stack frame is set up. */ +void vSerialISR( void ); + + +void vSerialISR( void ) +{ +signed portCHAR cChar; +portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + + /* What caused the interrupt? */ + switch( U3IIR & serINTERRUPT_SOURCE_MASK ) + { + case serSOURCE_ERROR : /* Not handling this, but clear the interrupt. */ + cChar = U3LSR; + break; + + case serSOURCE_THRE : /* The THRE is empty. If there is another + character in the Tx queue, send it now. */ + + if (uart3TxRunning == 0) + { + RXD_RS485(); /* we are done sending, we have to receive now. */ + } + else + { + TXD_RS485(); /* we are still sending */ + } +#if 0 + if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE ) + { + //TXD_RS485(); /* send */ + U3THR = cChar; + RXD_RS485(); + } + else + { + /* There are no further characters + queued to send so we can indicate + that the THRE is available. */ + lTHREEmpty = pdTRUE; + + /* the queue is empty, the FIFO is empty. switch to RXD, + * so we can receive the response from the network. + */ + RXD_RS485(); + + } + break; + +#endif + + + case serSOURCE_RX_TIMEOUT : + case serSOURCE_RX : /* A character was received. Place it in + the queue of received characters. */ + cChar = U3RBR; + xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken ); + break; + + default : /* There is nothing to do, leave the ISR. */ + break; + } + + + /* Clear the ISR in the VIC. */ + VICVectAddr = serCLEAR_VIC_INTERRUPT; + + + /* Exit the ISR. If a task was woken by either a character being received + or transmitted then a context switch will occur. */ + + portYIELD_FROM_ISR(); + //portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ); + + +} +/*-----------------------------------------------------------*/ + +void vUART3_ISR_Wrapper( void ) +{ + /* Save the context of the interrupted task. */ + portSAVE_CONTEXT(); + + /* Call the handler function. This must be separate from the wrapper + function to ensure the correct stack frame is set up. */ + vSerialISR(); + + /* Restore the context of whichever task is going to run next. */ + portRESTORE_CONTEXT(); +} + + + + + +/*-----------------------------------------------------------*/ + +xComPortHandle xSerialPortInitMinimal( unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength ) +{ + + + unsigned int baud = 57600; + unsigned int divisor = get_uart_clk(3, OSCILLATOR_CLOCK_FREQUENCY) / (16 * baud); + + + +unsigned portLONG ulDivisor, ulWantedClock; +xComPortHandle xReturn = serHANDLE; +extern void ( vSerialISREntry) ( void ); + + /* Create the queues used to hold Rx and Tx characters. */ + xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) ); + xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) ); + + /* Initialise the THRE empty flag. */ + lTHREEmpty = pdTRUE; + + if( + ( xRxedChars != serINVALID_QUEUE ) && + ( xCharsForTx != serINVALID_QUEUE ) && + ( ulWantedBaud != ( unsigned portLONG ) 0 ) + ) + { + portENTER_CRITICAL(); + { + /* Setup the baud rate: Calculate the divisor value. */ + ulWantedClock = ulWantedBaud * serWANTED_CLOCK_SCALING; + ulDivisor = configCPU_CLOCK_HZ / ulWantedClock; + + + // xxxx xx1x xxxx xxxx xxxx xxxx xxxx xxxx + PCONP |= 0x02000000; // UART3 Power-ON + + + + /* Configure UART */ + + + U3LCR = 0x83; // 8 bits, no Parity, 1 Stop bit + + U3DLL = divisor & 0xFF; + + U3DLM = (divisor >> 8) & 0xFF; + + /* Turn on the FIFO's and clear the buffers. */ + U3FCR = ( serFIFO_ON | serCLEAR_FIFO ); + + + U3LCR = 0x03; + + /* Setup the VIC for the UART. */ + VICVectAddr29 = (portLONG) vUART3_ISR_Wrapper; /* UART3 interrupt handler */ + VICIntEnable |= (1<<29); /* Enable VIC index-29 (sUART3) */ + + /* Enable UART3 interrupts. */ + U3IER |= serENABLE_INTERRUPTS; + } + portEXIT_CRITICAL(); + + xReturn = ( xComPortHandle ) 1; + } + else + { + xReturn = ( xComPortHandle ) 0; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime ) +{ + /* The port handle is not required as this driver only supports UART3. */ + ( void ) pxPort; + + /* Get the next character from the buffer. Return false if no characters + are available, or arrive before xBlockTime expires. */ + if( xQueueReceive( xRxedChars, pcRxedChar, xBlockTime ) ) + { + return pdTRUE; + } + else + { + return pdFALSE; + } +} +/*-----------------------------------------------------------*/ + +void vSerialPutString( xComPortHandle pxPort, const signed portCHAR * const pcString, unsigned portSHORT usStringLength ) +{ +signed portCHAR *pxNext; + + /* NOTE: This implementation does not handle the queue being full as no + block time is used! */ + + /* The port handle is not required as this driver only supports UART0. */ + ( void ) pxPort; + ( void ) usStringLength; + + /* Send each character in the string, one at a time. */ + pxNext = ( signed portCHAR * ) pcString; + while( *pxNext ) + { + xSerialPutChar( pxPort, *pxNext, serNO_BLOCK ); + pxNext++; + } +} +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed portCHAR cOutChar, portTickType xBlockTime ) +{ +signed portBASE_TYPE xReturn; + + /* The port handle is not required as this driver only supports UART3. */ + ( void ) pxPort; + + portENTER_CRITICAL(); + { + /* Is there space to write directly to the UART? */ + if( lTHREEmpty == ( portLONG ) pdTRUE ) + { + /* We wrote the character directly to the UART, so was + successful. */ + lTHREEmpty = pdFALSE; + //TXD_RS485(); + U3THR = cOutChar; + //RXD_RS485(); + xReturn = pdPASS; + } + else + { + /* We cannot write directly to the UART, so queue the character. + Block for a maximum of xBlockTime if there is no space in the + queue. It is ok to block within a critical section as each + task has it's own critical section management. */ + xReturn = xQueueSend( xCharsForTx, &cOutChar, xBlockTime ); + + /* Depending on queue sizing and task prioritisation: While we + were blocked waiting to post interrupts were not disabled. It is + possible that the serial ISR has emptied the Tx queue, in which + case we need to start the Tx off again. */ + if( lTHREEmpty == ( portLONG ) pdTRUE ) + { + xQueueReceive( xCharsForTx, &cOutChar, serNO_BLOCK ); + lTHREEmpty = pdFALSE; + //TXD_RS485(); + U3THR = cOutChar; + //RXD_RS485(); + } + } + } + portEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + Index: webserver/example/EnergyMeters/Source/EnergyMeters/Meters.c =================================================================== --- webserver/example/EnergyMeters/Source/EnergyMeters/Meters.c (revision 30) +++ webserver/example/EnergyMeters/Source/EnergyMeters/Meters.c (revision 37) @@ -36,13 +36,22 @@ vSemaphoreCreateBinary( xMetersSemaphore ); - Init_P2_0(); /* init GPIO for meters */ + //Init_P2_0(); /* init GPIO for meters */ + // TODO: put this in again, right now it interferes with Solar UART3! + for( ;; ) { + /* this runs every 1000 ms */ + basementGasCalculation(); + + + portENTER_CRITICAL(); // example: do stuff + + portEXIT_CRITICAL(); @@ -79,7 +88,4 @@ void vP2_0_ISR_Wrapper( void ); - -// configure port-pins for use with LAN-controller, -// reset it and send the configuration-sequence portBASE_TYPE Init_P2_0(void) Index: webserver/example/EnergyMeters/Source/EnergyMeters/SolarCountUART.c =================================================================== --- webserver/example/EnergyMeters/Source/EnergyMeters/SolarCountUART.c (revision 35) +++ webserver/example/EnergyMeters/Source/EnergyMeters/SolarCountUART.c (revision 37) @@ -2,4 +2,14 @@ #include "LPC23xx.h" + + +#include "FreeRTOS.h" +#include "semphr.h" +#include "task.h" +#include "serial.h" + +#define solarSTACK_SIZE configMINIMAL_STACK_SIZE+200 + +#define SOLAR_READ_DELAY 500 // Pin I/O LED Control Maskbit @@ -17,9 +27,26 @@ #define SOL_CHAN 2 /* querying channel currentChannel */ #define SOL_CHAN_WAIT_REPLY 3 /* waiting for reply on channel currentChannel = 0; */ -#define SOL_FINISHED 10 /* finished */ +#define SOL_FINISHED 0xA /* finished */ //#define SOL_ //#define SOL_ +// UART/FIFO Register Bit Masks + +#define UIIR_PEND 1U +#define UIIR_RLS_INT (3U << 1) +#define UIIR_RDA_INT (2U << 1) +#define UIIR_CTI_INT (6U << 1) +#define UIIR_THRE_INT (1U << 1) + +#define ULSR_RDR 1U + + +/* Handle to the com port (UART3) */ + xComPortHandle xPort; + +unsigned int uart3TxRunning = 0; /* flag to tell if we are currently sending a datagram */ + + unsigned int rxBuf3NextFreeRxPos = 0; @@ -27,4 +54,7 @@ static int solarState = SOL_NO_INIT; /* state of the SolarCount communication state machine */ + + +portTickType xReadRate, xLastReadTime; @@ -97,31 +127,17 @@ void TXD_RS485(void) { - delay(500000); + //delay(500000); IOSET1 = DIR_RS485; // RS485 Direction = 1 (Transmit) } /* TXD_RS485 */ - -void testUART3(void) -{ - int k; - int RxBuf; // one rx char - int uart_data; // Character Receive Buffer - k = 0; - - +void initSolarFSM(void) +{ + xLastReadTime = xTaskGetTickCount(); solarState = SOL_NO_INIT; - while (1) - { - - solarFSM(); - - if (solarState == SOL_FINISHED) - { - solarState = SOL_NO_INIT; - } /* if */ - } /* while */ - -} + init_serial3(); +} /* initSolarFSM */ + + /* Clear Uart3 RxBuf and pointer to next Rx element */ @@ -140,14 +156,25 @@ void getUart3RxData(void) { - + signed portBASE_TYPE byteReceived; /* did we receive a byte? */ + + const portTickType xBlockTime = ( portTickType ) 0; /* ( portTickType ) 0xffff / portTICK_RATE_MS; */ unsigned char RxBuf; // one rx char, or 0x100 if no data - unsigned char rxTrue; // did we receive a byte? + //unsigned char rxTrue; // did we receive a byte? while (rxBuf3NextFreeRxPos + 1 < RX_UART3_BUF_SIZE) { - /* while not overran */ - - RxBuf = getchar3(&rxTrue); - if (rxTrue == 1) + /* while not overrun */ + + //RxBuf = getchar3(&rxTrue); + + byteReceived = xSerialGetChar( xPort, &RxBuf, xBlockTime ); + + + if ((rxBuf3NextFreeRxPos == 0) && (byteReceived == pdTRUE) && (RxBuf == 0x00)) + { + /* we are at position 0, and we have received a 0x00 byte. ignore this leading 0. */ + ; /* do nothing */ + } + else if (byteReceived == pdTRUE) { // if data available @@ -168,31 +195,52 @@ int i; - if (n > RX_UART3_BUF_SIZE) - { - /* n too large */ - resetUart3RxBuf (); - return; - } + // for now, clear the whole buffer + resetUart3RxBuf(); + + + // begin quickfix (TODO) + + + + //if (n > RX_UART3_BUF_SIZE) + //{ + // /* n too large */ + + + //resetUart3RxBuf (); + + + + // return; + //} /* move end part of the buffer (after n) to front */ - for (i = 0; i < n; i++) - { - rxUART3[i] = rxUART3[i+n]; // move byte - } + //for (i = 0; i < n; i++) + //{ + // rxUART3[i] = rxUART3[i+n]; // move byte + //} /* write 0 to now unused elements */ - for (i = n; i < RX_UART3_BUF_SIZE; i++) - { - rxUART3[i] = 0; // clear byte - } + //for (i = n; i < RX_UART3_BUF_SIZE; i++) + //{ + // rxUART3[i] = 0; // clear byte + //} + + /* clear all elements */ + + + + /* adjust rxBuf3NextFreeRxPos */ - if (n >= rxBuf3NextFreeRxPos) - { - /* remove more elements than are in the buffer */ - rxBuf3NextFreeRxPos = 0; // buffer empty - } - else - { - rxBuf3NextFreeRxPos -= n; - } -} /* chopUart3RxBuf */ + //if (n >= rxBuf3NextFreeRxPos) + //{ + // /* remove more elements than are in the buffer */ + // rxBuf3NextFreeRxPos = 0; // buffer empty + //} + //else + //{ + // rxBuf3NextFreeRxPos -= n; + //} + // end quickfix (TODO) + +}/* chopUart3RxBuf */ @@ -263,4 +311,5 @@ int cmpResult; + /* always get Rx data */ getUart3RxData(); @@ -269,14 +318,9 @@ { case SOL_NO_INIT: - delay(500000); - init_serial3(); resetUart3RxBuf(); /* init */ currentChannel = 0; /* the channel we query first */ - TXD_RS485(); - delay(500000); /* send init 1 */ send_uart3((unsigned char *)init1, sizeof(init1)); - RXD_RS485(); solarState = SOL_SENT_INIT; /* now wait for reply */ break; @@ -310,5 +354,5 @@ /* send query for channel number currentChannel */ - TXD_RS485(); + vTaskDelayUntil( &xLastReadTime, SOLAR_READ_DELAY ); switch ( currentChannel ) { @@ -338,5 +382,4 @@ ; /* do nothing */ } /* switch */ - RXD_RS485(); if (solarState != SOL_FINISHED) { @@ -395,5 +438,5 @@ /* finally, discard data from buffer */ - resetUart3RxBuf(); + /* switch to next channel */ @@ -408,4 +451,6 @@ } + resetUart3RxBuf(); + } else @@ -425,13 +470,11 @@ -/********************************/ -/* Initial UART3 = 115200,N,8,1 */ -/********************************/ + void init_serial3 (void) { + unsigned int baud = 57600; unsigned int divisor = get_uart_clk(3, OSCILLATOR_CLOCK_FREQUENCY) / (16 * baud); - int i; @@ -441,4 +484,7 @@ } + /* init serial port */ + xPort = xSerialPortInitMinimal( baud /* baud rate */, 80 /* buffer length */ ); +//vStartComTestTasks(); // xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1010 @@ -453,5 +499,5 @@ PINSEL3 &= 0xFFFF3FFF; // P1.19 = GPIO IODIR1 = DIR_RS485; // Pin Control Direction RS485 = Output - RXD_RS485(); // Default RS485 Direction + //RXD_RS485(); // Default RS485 Direction //PCLKSEL1 = 0; /* UART3 frequency */ @@ -474,14 +520,4 @@ // Baud Rate Calculator: http://prototalk.net/forums/showthread.php?t=11 - -#if 0 - U3LCR = 0x83; // 8 bits, no Parity, 1 Stop bit - U3DLL = 0x0C; // Baud 57600BPS for 12MHz PCLK Clock - U3FDR = 0xC1; // Fractional Divider (0x67 = 115200 , 0xCE = 57600 ????), - U3DLM = 0; - - U3LCR = 0x03; // DLAB = 0 -#endif - @@ -496,18 +532,24 @@ void send_uart3(char * data, int length) { - int i = 0; // Pointer Buffer - - TXD_RS485(); // Swap RS485 Direction = Transmit - delay(50000); - - - for (i = 0; i < length-1; i++) // Get char & Print Until null - { + + + int i = 0; // Pointer Buffer + + TXD_RS485(); + //delay(50000); + + uart3TxRunning = 1; // sending in progress + for (i = 0; i < length-1; i++) // Get char & Print Until null + { + /* go only through length-1 because we do not send the terminating \x00 of the c-string in data */ - putchar3(data[i]); // Write char to UART // Next char + putchar3(data[i]); // Write char to UART } - - delay(50000); - RXD_RS485(); // Swap RS485 Direction = Receive + uart3TxRunning = 0; // done sending this datagram. The UART interrupt can switch to Rx as soon as FIFO is empty + + + // we send directly. unused. + // vSerialPutString( xPort, &(data[0]), length-1 ); + return; @@ -555,2 +597,39 @@ } + + +static portTASK_FUNCTION( vSolar_Task, pvParameters ) +{ + + + initSolarFSM(); + + for( ;; ) + { + + + + //portENTER_CRITICAL(); + + solarFSM(); + + //portEXIT_CRITICAL(); + + + if (solarState == SOL_FINISHED) + { + solarState = SOL_NO_INIT; + } /* if */ + + } +} + + + +void vStartSolarTask( unsigned portBASE_TYPE uxPriority ) +{ + + /* Spawn the task. */ + xTaskCreate( vSolar_Task, ( signed portCHAR * ) "Solar", solarSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL ); +} +