]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/PIC18_MPLAB/serial/serial.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / PIC18_MPLAB / serial / serial.c
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /*\r
30 Changes from V1.2.5\r
31 \r
32         +  Clear overrun errors in the Rx ISR.  Overrun errors prevent any further\r
33            characters being received.\r
34 \r
35 Changes from V2.0.0\r
36 \r
37         + Use TickType_t in place of unsigned pdLONG for delay periods.\r
38         + cQueueReieveFromISR() used in place of xQueueReceive() in ISR.\r
39 */\r
40 \r
41 /* BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER. */\r
42 \r
43 /* Scheduler header files. */\r
44 #include "FreeRTOS.h"\r
45 #include "task.h"\r
46 #include "serial.h"\r
47 #include "queue.h"\r
48 \r
49 /*\r
50  * Prototypes for ISR's.  The PIC architecture means that these functions\r
51  * have to be called from port.c.  The prototypes are not however included\r
52  * in the header as the header is common to all ports.\r
53  */\r
54 void vSerialTxISR( void );\r
55 void vSerialRxISR( void );\r
56 \r
57 /* Hardware pin definitions. */\r
58 #define serTX_PIN       TRISCbits.TRISC6\r
59 #define serRX_PIN       TRISCbits.TRISC7\r
60 \r
61 /* Bit/register definitions. */\r
62 #define serINPUT                                ( 1 )\r
63 #define serOUTPUT                               ( 0 )\r
64 #define serTX_ENABLE                    ( ( unsigned short ) 1 )\r
65 #define serRX_ENABLE                    ( ( unsigned short ) 1 )\r
66 #define serHIGH_SPEED                   ( ( unsigned short ) 1 )\r
67 #define serCONTINUOUS_RX                ( ( unsigned short ) 1 )\r
68 #define serCLEAR_OVERRUN                ( ( unsigned short ) 0 )\r
69 #define serINTERRUPT_ENABLED    ( ( unsigned short ) 1 )\r
70 #define serINTERRUPT_DISABLED   ( ( unsigned short ) 0 )\r
71 \r
72 /* All ISR's use the PIC18 low priority interrupt. */\r
73 #define                                                 serLOW_PRIORITY ( 0 )\r
74 \r
75 /*-----------------------------------------------------------*/\r
76 \r
77 /* Queues to interface between comms API and interrupt routines. */\r
78 static QueueHandle_t xRxedChars; \r
79 static QueueHandle_t xCharsForTx;\r
80 \r
81 /*-----------------------------------------------------------*/\r
82 \r
83 xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )\r
84 {\r
85 unsigned long ulBaud;\r
86 \r
87         /* Calculate the baud rate generator constant.\r
88         SPBRG = ( (FOSC / Desired Baud Rate) / 16 ) - 1 */\r
89         ulBaud = configCPU_CLOCK_HZ / ulWantedBaud;\r
90         ulBaud /= ( unsigned long ) 16;\r
91         ulBaud -= ( unsigned long ) 1;\r
92 \r
93         /* Create the queues used by the ISR's to interface to tasks. */\r
94         xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( char ) );\r
95         xCharsForTx = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( char ) );\r
96 \r
97         portENTER_CRITICAL();\r
98         {\r
99                 /* Start with config registers cleared, so we can just set the wanted\r
100                 bits. */\r
101                 TXSTA = ( unsigned short ) 0;\r
102                 RCSTA = ( unsigned short ) 0;\r
103 \r
104                 /* Set the baud rate generator using the above calculated constant. */\r
105                 SPBRG = ( unsigned char ) ulBaud;\r
106 \r
107                 /* Setup the IO pins to enable the USART IO. */\r
108                 serTX_PIN = serOUTPUT;\r
109                 serRX_PIN = serINPUT;\r
110 \r
111                 /* Set the serial interrupts to use the same priority as the tick. */\r
112                 IPR1bits.TXIP = serLOW_PRIORITY;\r
113                 IPR1bits.RCIP = serLOW_PRIORITY;\r
114 \r
115                 /* Setup Tx configuration. */\r
116                 TXSTAbits.BRGH = serHIGH_SPEED;\r
117                 TXSTAbits.TXEN = serTX_ENABLE;\r
118 \r
119                 /* Setup Rx configuration. */\r
120                 RCSTAbits.SPEN = serRX_ENABLE;\r
121                 RCSTAbits.CREN = serCONTINUOUS_RX;\r
122 \r
123                 /* Enable the Rx interrupt now, the Tx interrupt will get enabled when\r
124                 we have data to send. */\r
125                 PIE1bits.RCIE = serINTERRUPT_ENABLED;\r
126         }\r
127         portEXIT_CRITICAL();\r
128 \r
129         /* Unlike other ports, this serial code does not allow for more than one\r
130         com port.  We therefore don't return a pointer to a port structure and \r
131         can     instead just return NULL. */\r
132         return NULL;\r
133 }\r
134 /*-----------------------------------------------------------*/\r
135 \r
136 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )\r
137 {\r
138         /* This is not implemented in this port.\r
139         Use xSerialPortInitMinimal() instead. */\r
140 }\r
141 /*-----------------------------------------------------------*/\r
142 \r
143 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed char *pcRxedChar, TickType_t xBlockTime )\r
144 {\r
145         /* Get the next character from the buffer.  Return false if no characters\r
146         are available, or arrive before xBlockTime expires. */\r
147         if( xQueueReceive( xRxedChars, pcRxedChar, xBlockTime ) )\r
148         {\r
149                 return pdTRUE;\r
150         }\r
151         else\r
152         {\r
153                 return pdFALSE;\r
154         }\r
155 }\r
156 /*-----------------------------------------------------------*/\r
157 \r
158 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, TickType_t xBlockTime )\r
159 {\r
160         /* Return false if after the block time there is no room on the Tx queue. */\r
161         if( xQueueSend( xCharsForTx, ( const void * ) &cOutChar, xBlockTime ) != pdPASS )\r
162         {\r
163                 return pdFAIL;\r
164         }\r
165 \r
166         /* Turn interrupt on - ensure the compiler only generates a single \r
167         instruction for this. */\r
168         PIE1bits.TXIE = serINTERRUPT_ENABLED;\r
169 \r
170         return pdPASS;\r
171 }\r
172 /*-----------------------------------------------------------*/\r
173 \r
174 void vSerialClose( xComPortHandle xPort )\r
175 {\r
176         /* Not implemented for this port.\r
177         To implement, turn off the interrupts and delete the memory\r
178         allocated to the queues. */\r
179 }\r
180 /*-----------------------------------------------------------*/\r
181 \r
182 #pragma interruptlow vSerialRxISR save=PRODH, PRODL, TABLAT, section(".tmpdata")\r
183 void vSerialRxISR( void )\r
184 {\r
185 char cChar;\r
186 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
187 \r
188         /* Get the character and post it on the queue of Rxed characters.\r
189         If the post causes a task to wake force a context switch as the woken task\r
190         may have a higher priority than the task we have interrupted. */\r
191         cChar = RCREG;\r
192 \r
193         /* Clear any overrun errors. */\r
194         if( RCSTAbits.OERR )\r
195         {\r
196                 RCSTAbits.CREN = serCLEAR_OVERRUN;\r
197                 RCSTAbits.CREN = serCONTINUOUS_RX;      \r
198         }\r
199 \r
200         xQueueSendFromISR( xRxedChars, ( const void * ) &cChar, &xHigherPriorityTaskWoken );\r
201 \r
202         if( xHigherPriorityTaskWoken )\r
203         {\r
204                 taskYIELD();\r
205         }\r
206 }\r
207 /*-----------------------------------------------------------*/\r
208 \r
209 #pragma interruptlow vSerialTxISR save=PRODH, PRODL, TABLAT, section(".tmpdata")\r
210 void vSerialTxISR( void )\r
211 {\r
212 char cChar, cTaskWoken = pdFALSE;\r
213 \r
214         if( xQueueReceiveFromISR( xCharsForTx, &cChar, &cTaskWoken ) == pdTRUE )\r
215         {\r
216                 /* Send the next character queued for Tx. */\r
217                 TXREG = cChar;\r
218         }\r
219         else\r
220         {\r
221                 /* Queue empty, nothing to send. */\r
222                 PIE1bits.TXIE = serINTERRUPT_DISABLED;\r
223         }\r
224 }\r
225 \r
226 \r
227 \r