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