]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Output/uartOut/arm/uart_serial.c
Merge branch 'master' of github.com:kiibohd/controller
[kiibohd-controller.git] / Output / uartOut / arm / uart_serial.c
1 /* Copyright (C) 2014-2015 by Jacob Alexander
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  */
21
22 // ----- Includes -----
23
24 // Compiler Includes
25 #include <string.h> // For memcpy
26
27 // Project Includes
28 #include <Lib/OutputLib.h>
29 #include <Lib/Interrupts.h>
30 #include <print.h>
31 #include <kll_defs.h>
32
33 // Local Includes
34 #include "uart_serial.h"
35
36
37
38 // ----- Defines -----
39
40 // UART Configuration
41 #if defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // UART0 Debug
42 #define UART_BDH    UART0_BDH
43 #define UART_BDL    UART0_BDL
44 #define UART_C1     UART0_C1
45 #define UART_C2     UART0_C2
46 #define UART_C3     UART0_C3
47 #define UART_C4     UART0_C4
48 #define UART_CFIFO  UART0_CFIFO
49 #define UART_D      UART0_D
50 #define UART_PFIFO  UART0_PFIFO
51 #define UART_RCFIFO UART0_RCFIFO
52 #define UART_RWFIFO UART0_RWFIFO
53 #define UART_S1     UART0_S1
54 #define UART_S2     UART0_S2
55 #define UART_SFIFO  UART0_SFIFO
56 #define UART_TWFIFO UART0_TWFIFO
57
58 #define SIM_SCGC4_UART  SIM_SCGC4_UART0
59 #define IRQ_UART_STATUS IRQ_UART0_STATUS
60
61 #elif defined(_mk20dx256vlh7_) // UART2 Debug
62 #define UART_BDH    UART2_BDH
63 #define UART_BDL    UART2_BDL
64 #define UART_C1     UART2_C1
65 #define UART_C2     UART2_C2
66 #define UART_C3     UART2_C3
67 #define UART_C4     UART2_C4
68 #define UART_CFIFO  UART2_CFIFO
69 #define UART_D      UART2_D
70 #define UART_PFIFO  UART2_PFIFO
71 #define UART_RCFIFO UART2_RCFIFO
72 #define UART_RWFIFO UART2_RWFIFO
73 #define UART_S1     UART2_S1
74 #define UART_S2     UART2_S2
75 #define UART_SFIFO  UART2_SFIFO
76 #define UART_TWFIFO UART2_TWFIFO
77
78 #define SIM_SCGC4_UART  SIM_SCGC4_UART2
79 #define IRQ_UART_STATUS IRQ_UART2_STATUS
80
81 #endif
82
83
84
85 // ----- Variables -----
86
87 #define uart_buffer_size 128 // 128 byte buffer
88 volatile uint8_t uart_buffer_head = 0;
89 volatile uint8_t uart_buffer_tail = 0;
90 volatile uint8_t uart_buffer_items = 0;
91 volatile uint8_t uart_buffer[uart_buffer_size];
92
93 volatile uint8_t uart_configured = 0;
94
95
96
97 // ----- Interrupt Functions -----
98
99 #if defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // UART0 Debug
100 void uart0_status_isr()
101 #elif defined(_mk20dx256vlh7_) // UART2 Debug
102 void uart2_status_isr()
103 #endif
104 {
105         cli(); // Disable Interrupts
106
107         // UART0_S1 must be read for the interrupt to be cleared
108         if ( UART_S1 & ( UART_S1_RDRF | UART_S1_IDLE ) )
109         {
110                 uint8_t available = UART_RCFIFO;
111
112                 // If there was actually nothing
113                 if ( available == 0 )
114                 {
115                         // Cleanup
116                         available = UART_D;
117                         UART_CFIFO = UART_CFIFO_RXFLUSH;
118                         goto done;
119                 }
120
121                 // Read UART0 into buffer until FIFO is empty
122                 while ( available-- > 0 )
123                 {
124                         uart_buffer[uart_buffer_tail++] = UART_D;
125                         uart_buffer_items++;
126
127                         // Wrap-around of tail pointer
128                         if ( uart_buffer_tail >= uart_buffer_size )
129                         {
130                                 uart_buffer_tail = 0;
131                         }
132
133                         // Make sure the head pointer also moves if circular buffer is overwritten
134                         if ( uart_buffer_head == uart_buffer_tail )
135                         {
136                                 uart_buffer_head++;
137                         }
138
139                         // Wrap-around of head pointer
140                         if ( uart_buffer_head >= uart_buffer_size )
141                         {
142                                 uart_buffer_head = 0;
143                         }
144                 }
145         }
146
147 done:
148         sei(); // Re-enable Interrupts
149 }
150
151
152
153 // ----- Functions -----
154
155 void uart_serial_setup()
156 {
157         // Indication that the UART is not ready yet
158         uart_configured = 0;
159
160         // Setup the the UART interface for keyboard data input
161         SIM_SCGC4 |= SIM_SCGC4_UART; // Disable clock gating
162
163 // MCHCK / Kiibohd-dfu
164 #if defined(_mk20dx128vlf5_)
165         // Pin Setup for UART0
166         PORTA_PCR1 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); // RX Pin
167         PORTA_PCR2 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); // TX Pin
168
169 // Kiibohd-dfu
170 #elif defined(_mk20dx256vlh7_)
171         // Pin Setup for UART2
172         PORTD_PCR2 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
173         PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
174
175 // Teensy
176 #else
177         // Pin Setup for UART0
178         PORTB_PCR16 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
179         PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
180 #endif
181
182
183 #if defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // UART0 Debug
184         // Setup baud rate - 115200 Baud
185         // 48 MHz / ( 16 * Baud ) = BDH/L
186         // Baud: 115200 -> 48 MHz / ( 16 * 115200 ) = 26.0416667
187         // Thus baud setting = 26
188         // NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
189         uint16_t baud = 26; // Max setting of 8191
190         UART_BDH = (uint8_t)(baud >> 8);
191         UART_BDL = (uint8_t)baud;
192         UART_C4 = 0x02;
193
194 #elif defined(_mk20dx256vlh7_) // UART2 Debug
195         // Setup baud rate - 115200 Baud
196         // Uses Bus Clock
197         // 36 MHz / ( 16 * Baud ) = BDH/L
198         // Baud: 115200 -> 36 MHz / ( 16 * 115200 ) = 19.53125
199         // Thus baud setting = 19
200         // NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
201         uint16_t baud = 19; // Max setting of 8191
202         UART_BDH = (uint8_t)(baud >> 8);
203         UART_BDL = (uint8_t)baud;
204         UART_C4 = 0x11;
205
206 #endif
207
208         // 8 bit, No Parity, Idle Character bit after stop
209         UART_C1 = UART_C1_ILT;
210
211         // Interrupt notification watermarks
212 #if defined(_mk20dx128_) || defined(_mk20dx128vlf5_) || defined(_mk20dx256_) // UART0 Debug
213         UART_TWFIFO = 2;
214         UART_RWFIFO = 4;
215 #elif defined(_mk20dx256vlh7_) // UART2 Debug
216         // UART2 has a single byte FIFO
217         UART_TWFIFO = 1;
218         UART_RWFIFO = 1;
219 #endif
220
221         // TX FIFO Enabled, TX FIFO Size 1 (Max 8 datawords), RX FIFO Enabled, RX FIFO Size 1 (Max 8 datawords)
222         // TX/RX FIFO Size:
223         //  0x0 - 1 dataword
224         //  0x1 - 4 dataword
225         //  0x2 - 8 dataword
226         UART_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
227
228         // Reciever Inversion Disabled, LSBF
229         // UART_S2_RXINV UART_S2_MSBF
230         UART_S2 |= 0x00;
231
232         // Transmit Inversion Disabled
233         // UART_C3_TXINV
234         UART_C3 |= 0x00;
235
236         // TX Enabled, RX Enabled, RX Interrupt Enabled, Generate idles
237         // UART_C2_TE UART_C2_RE UART_C2_RIE UART_C2_ILIE
238         UART_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE | UART_C2_ILIE;
239
240         // Add interrupt to the vector table
241         NVIC_ENABLE_IRQ( IRQ_UART_STATUS );
242
243         // UART is now ready to use
244         uart_configured = 1;
245 }
246
247
248 // Get the next character, or -1 if nothing received
249 int uart_serial_getchar()
250 {
251         if ( !uart_configured )
252                 return -1;
253
254         unsigned int value = -1;
255
256         // Check to see if the FIFO has characters
257         if ( uart_buffer_items > 0 )
258         {
259                 value = uart_buffer[uart_buffer_head++];
260                 uart_buffer_items--;
261
262                 // Wrap-around of head pointer
263                 if ( uart_buffer_head >= uart_buffer_size )
264                 {
265                         uart_buffer_head = 0;
266                 }
267         }
268
269         return value;
270 }
271
272
273 // Number of bytes available in the receive buffer
274 int uart_serial_available()
275 {
276         return uart_buffer_items;
277 }
278
279
280 // Discard any buffered input
281 void uart_serial_flush_input()
282 {
283         uart_buffer_head = 0;
284         uart_buffer_tail = 0;
285         uart_buffer_items = 0;
286 }
287
288
289 // Transmit a character.  0 returned on success, -1 on error
290 int uart_serial_putchar( uint8_t c )
291 {
292         if ( !uart_configured )
293                 return -1;
294
295         while ( !( UART_SFIFO & UART_SFIFO_TXEMPT ) ); // Wait till there is room to send
296         UART_D = c;
297
298         return 0;
299 }
300
301
302 int uart_serial_write( const void *buffer, uint32_t size )
303 {
304         if ( !uart_configured )
305                 return -1;
306
307         const uint8_t *data = (const uint8_t *)buffer;
308         uint32_t position = 0;
309
310         // While buffer is not empty and transmit buffer is
311         while ( position < size )
312         {
313                 while ( !( UART_SFIFO & UART_SFIFO_TXEMPT ) ); // Wait till there is room to send
314                 UART_D = data[position++];
315         }
316
317         return 0;
318 }
319
320
321 void uart_serial_flush_output()
322 {
323         // Delay until buffer has been sent
324         while ( !( UART_SFIFO & UART_SFIFO_TXEMPT ) ); // Wait till there is room to send
325 }
326
327
328 void uart_device_reload()
329 {
330         if ( flashModeEnabled_define == 0 )
331         {
332                 print( NL );
333                 warn_print("flashModeEnabled not set, cancelling firmware reload...");
334                 info_msg("Set flashModeEnabled to 1 in your kll configuration.");
335                 return;
336         }
337
338 // MCHCK
339 #if defined(_mk20dx128vlf5_)
340
341         // MCHCK Kiibohd Variant
342         // Check to see if PTA3 (has a pull-up) is connected to GND (usually via jumper)
343         // Only allow reload if the jumper is present (security)
344         GPIOA_PDDR &= ~(1<<3); // Input
345         PORTA_PCR3 = PORT_PCR_PFE | PORT_PCR_MUX(1); // Internal pull-up
346
347         // Check for jumper
348         if ( GPIOA_PDIR & (1<<3) && flashModeEnabled_define != 0 )
349         {
350                 print( NL );
351                 warn_print("Security jumper not present, cancelling firmware reload...");
352                 info_msg("Replace jumper on middle 2 pins, or manually press the firmware reload button.");
353         }
354         else
355         {
356                 // Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode
357                 for ( int pos = 0; pos < sizeof(sys_reset_to_loader_magic); pos++ )
358                         (&VBAT)[ pos ] = sys_reset_to_loader_magic[ pos ];
359                 SOFTWARE_RESET();
360         }
361
362 // Kiibohd mk20dx256vlh7
363 #elif defined(_mk20dx256vlh7_)
364         // Copies variable into the VBAT register, must be identical to the variable in the bootloader to jump to the bootloader flash mode
365         for ( int pos = 0; pos < sizeof(sys_reset_to_loader_magic); pos++ )
366                 (&VBAT)[ pos ] = sys_reset_to_loader_magic[ pos ];
367         SOFTWARE_RESET();
368
369 // Teensy 3.0 and 3.1
370 #else
371         asm volatile("bkpt");
372 #endif
373 }
374