]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Output/uartOut/arm/uart_serial.c
Fixed bug with standalone UART CLI
[kiibohd-controller.git] / Output / uartOut / arm / uart_serial.c
1 /* Copyright (C) 2014 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 #include "uart_serial.h"
23 #include <Lib/OutputLib.h>
24 #include <Lib/Interrupts.h>
25 #include <string.h> // For memcpy
26
27 // ----- Variables -----
28
29 #define uart0_buffer_size 128 // 128 byte buffer
30 volatile uint8_t uart0_buffer_head = 0;
31 volatile uint8_t uart0_buffer_tail = 0;
32 volatile uint8_t uart0_buffer_items = 0;
33 volatile uint8_t uart0_buffer[uart0_buffer_size];
34
35 volatile uint8_t uart_configured = 0;
36
37
38
39 // ----- Interrupt Functions -----
40
41 void uart0_status_isr()
42 {
43         cli(); // Disable Interrupts
44
45         // UART0_S1 must be read for the interrupt to be cleared
46         if ( UART0_S1 & ( UART_S1_RDRF | UART_S1_IDLE ) )
47         {
48                 uint8_t available = UART0_RCFIFO;
49
50                 // If there was actually nothing
51                 if ( available == 0 )
52                 {
53                         // Cleanup
54                         available = UART0_D;
55                         UART0_CFIFO = UART_CFIFO_RXFLUSH;
56                         sei();
57                         return;
58                 }
59
60                 // Read UART0 into buffer until FIFO is empty
61                 while ( available-- > 0 )
62                 {
63                         uart0_buffer[uart0_buffer_tail++] = UART0_D;
64                         uart0_buffer_items++;
65
66                         // Wrap-around of tail pointer
67                         if ( uart0_buffer_tail >= uart0_buffer_size )
68                         {
69                                 uart0_buffer_tail = 0;
70                         }
71
72                         // Make sure the head pointer also moves if circular buffer is overwritten
73                         if ( uart0_buffer_head == uart0_buffer_tail )
74                         {
75                                 uart0_buffer_head++;
76                         }
77
78                         // Wrap-around of head pointer
79                         if ( uart0_buffer_head >= uart0_buffer_size )
80                         {
81                                 uart0_buffer_head = 0;
82                         }
83                 }
84         }
85
86         sei(); // Re-enable Interrupts
87 }
88
89
90
91 // ----- Functions -----
92
93 void uart_serial_setup()
94 {
95         // Indication that the UART is not ready yet
96         uart_configured = 0;
97
98         // Setup the the UART interface for keyboard data input
99         SIM_SCGC4 |= SIM_SCGC4_UART0; // Disable clock gating
100
101         // Pin Setup for UART0
102         PORTB_PCR16 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
103         PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
104
105         // Setup baud rate - 115200 Baud
106         // 48 MHz / ( 16 * Baud ) = BDH/L
107         // Baud: 115200 -> 48 MHz / ( 16 * 115200 ) = 26.0416667
108         // Thus baud setting = 26
109         // NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
110         uint16_t baud = 26; // Max setting of 8191
111         UART0_BDH = (uint8_t)(baud >> 8);
112         UART0_BDL = (uint8_t)baud;
113         UART0_C4 = 0x02;
114
115         // 8 bit, No Parity, Idle Character bit after stop
116         UART0_C1 = UART_C1_ILT;
117
118         // Interrupt notification watermark
119         UART0_TWFIFO = 2;
120         UART0_RWFIFO = 4;
121
122         // TX FIFO Disabled, TX FIFO Size 1 (Max 8 datawords), RX FIFO Enabled, RX FIFO Size 1 (Max 8 datawords)
123         // TX/RX FIFO Size:
124         //  0x0 - 1 dataword
125         //  0x1 - 4 dataword
126         //  0x2 - 8 dataword
127         UART0_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
128
129         // Reciever Inversion Disabled, LSBF
130         // UART_S2_RXINV UART_S2_MSBF
131         UART0_S2 |= 0x00;
132
133         // Transmit Inversion Disabled
134         // UART_C3_TXINV
135         UART0_C3 |= 0x00;
136
137         // TX Enabled, RX Enabled, RX Interrupt Enabled, Generate idles
138         // UART_C2_TE UART_C2_RE UART_C2_RIE UART_C2_ILIE
139         UART0_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE | UART_C2_ILIE;
140
141         // Add interrupt to the vector table
142         NVIC_ENABLE_IRQ( IRQ_UART0_STATUS );
143
144         // UART is now ready to use
145         uart_configured = 1;
146 }
147
148
149 // Get the next character, or -1 if nothing received
150 int uart_serial_getchar()
151 {
152         if ( !uart_configured )
153                 return -1;
154
155         unsigned int value = -1;
156
157         // Check to see if the FIFO has characters
158         if ( uart0_buffer_items > 0 )
159         {
160                 value = uart0_buffer[uart0_buffer_head++];
161                 uart0_buffer_items--;
162
163                 // Wrap-around of head pointer
164                 if ( uart0_buffer_head >= uart0_buffer_size )
165                 {
166                         uart0_buffer_head = 0;
167                 }
168         }
169
170         return value;
171 }
172
173
174 // Number of bytes available in the receive buffer
175 int uart_serial_available()
176 {
177         return uart0_buffer_items;
178 }
179
180
181 // Discard any buffered input
182 void uart_serial_flush_input()
183 {
184         uart0_buffer_head = 0;
185         uart0_buffer_tail = 0;
186         uart0_buffer_items = 0;
187 }
188
189
190 // Transmit a character.  0 returned on success, -1 on error
191 int uart_serial_putchar( uint8_t c )
192 {
193         if ( !uart_configured )
194                 return -1;
195
196         while ( !( UART0_SFIFO & UART_SFIFO_TXEMPT ) ); // Wait till there is room to send
197         UART0_D = c;
198
199         return 0;
200 }
201
202
203 int uart_serial_write( const void *buffer, uint32_t size )
204 {
205         if ( !uart_configured )
206                 return -1;
207
208         const uint8_t *data = (const uint8_t *)buffer;
209         uint32_t position = 0;
210
211         // While buffer is not empty and transmit buffer is
212         while ( position < size )
213         {
214                 while ( !( UART0_SFIFO & UART_SFIFO_TXEMPT ) ); // Wait till there is room to send
215                 UART0_D = data[position++];
216         }
217
218         return 0;
219 }
220
221
222 void uart_serial_flush_output()
223 {
224         // Delay until buffer has been sent
225         while ( !( UART0_SFIFO & UART_SFIFO_TXEMPT ) ); // Wait till there is room to send
226 }
227
228
229 void uart_device_reload()
230 {
231         asm volatile("bkpt");
232 }
233