-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathuart.c
283 lines (258 loc) · 6.28 KB
/
uart.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/*! \file uart.c \brief UART driver with buffer support. */
// *****************************************************************************
//
// File Name : 'uart.c'
// Title : UART driver with buffer support
// Author : Pascal Stang - Copyright (C) 2000-2002
// Created : 11/22/2000
// Revised : 06/09/2003
// Version : 1.3
// Target MCU : ATMEL AVR Series
// Editor Tabs : 4
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// *****************************************************************************
#include <avr/io.h>
#include <avr/interrupt.h>
#include "buffer.h"
#include "uart.h"
// UART global variables
// flag variables
volatile u08 uartReadyTx; ///< uartReadyTx flag
volatile u08 uartBufferedTx; ///< uartBufferedTx flag
// receive and transmit buffers
cBuffer uartRxBuffer; ///< uart receive buffer
cBuffer uartTxBuffer; ///< uart transmit buffer
unsigned short uartRxOverflow; ///< receive overflow counter
#ifndef UART_BUFFERS_EXTERNAL_RAM
// using internal ram,
// automatically allocate space in ram for each buffer
static char uartRxData[UART_RX_BUFFER_SIZE];
static char uartTxData[UART_TX_BUFFER_SIZE];
#endif
typedef void (*voidFuncPtru08)(unsigned char);
volatile static voidFuncPtru08 UartRxFunc;
// enable and initialize the uart
void uartInit(void)
{
// initialize the buffers
uartInitBuffers();
// initialize user receive handler
UartRxFunc = 0;
// enable RxD/TxD and interrupts
outb(UCR, BV(RXCIE)|BV(TXCIE)|BV(RXEN)|BV(TXEN));
// set default baud rate
uartSetBaudRate(UART_DEFAULT_BAUD_RATE);
// initialize states
uartReadyTx = TRUE;
uartBufferedTx = FALSE;
// clear overflow count
uartRxOverflow = 0;
// enable interrupts
sei();
}
// create and initialize the uart transmit and receive buffers
void uartInitBuffers(void)
{
#ifndef UART_BUFFERS_EXTERNAL_RAM
// initialize the UART receive buffer
bufferInit(&uartRxBuffer, uartRxData, UART_RX_BUFFER_SIZE);
// initialize the UART transmit buffer
bufferInit(&uartTxBuffer, uartTxData, UART_TX_BUFFER_SIZE);
#else
// initialize the UART receive buffer
bufferInit(&uartRxBuffer, (u08*) UART_RX_BUFFER_ADDR, UART_RX_BUFFER_SIZE);
// initialize the UART transmit buffer
bufferInit(&uartTxBuffer, (u08*) UART_TX_BUFFER_ADDR, UART_TX_BUFFER_SIZE);
#endif
}
// redirects received data to a user function
void uartSetRxHandler(void (*rx_func)(unsigned char c))
{
// set the receive interrupt to run the supplied user function
UartRxFunc = rx_func;
}
// set the uart baud rate
void uartSetBaudRate(u32 baudrate)
{
// calculate division factor for requested baud rate, and set it
u16 bauddiv = ((F_CPU+(baudrate*8L))/(baudrate*16L)-1);
outb(UBRRL, bauddiv);
#ifdef UBRRH
outb(UBRRH, bauddiv>>8);
#endif
}
// returns the receive buffer structure
cBuffer* uartGetRxBuffer(void)
{
// return rx buffer pointer
return &uartRxBuffer;
}
// returns the transmit buffer structure
cBuffer* uartGetTxBuffer(void)
{
// return tx buffer pointer
return &uartTxBuffer;
}
// transmits a byte over the uart
void uartSendByte(u08 txData)
{
// wait for the transmitter to be ready
while(!uartReadyTx);
// send byte
outb(UDR, txData);
// set ready state to FALSE
uartReadyTx = FALSE;
}
// gets a single byte from the uart receive buffer (getchar-style)
int uartGetByte(void)
{
u08 c;
if(uartReceiveByte(&c))
return c;
else
return -1;
}
// gets a byte (if available) from the uart receive buffer
u08 uartReceiveByte(u08* rxData)
{
// make sure we have a receive buffer
if(uartRxBuffer.size)
{
// make sure we have data
if(uartRxBuffer.datalength)
{
// get byte from beginning of buffer
*rxData = bufferGetFromFront(&uartRxBuffer);
return TRUE;
}
else
{
// no data
return FALSE;
}
}
else
{
// no buffer
return FALSE;
}
}
// flush all data out of the receive buffer
void uartFlushReceiveBuffer(void)
{
// flush all data from receive buffer
//bufferFlush(&uartRxBuffer);
// same effect as above
uartRxBuffer.datalength = 0;
}
// return true if uart receive buffer is empty
u08 uartReceiveBufferIsEmpty(void)
{
if(uartRxBuffer.datalength == 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
// add byte to end of uart Tx buffer
u08 uartAddToTxBuffer(u08 data)
{
// add data byte to the end of the tx buffer
return bufferAddToEnd(&uartTxBuffer, data);
}
// start transmission of the current uart Tx buffer contents
void uartSendTxBuffer(void)
{
// turn on buffered transmit
uartBufferedTx = TRUE;
// send the first byte to get things going by interrupts
uartSendByte(bufferGetFromFront(&uartTxBuffer));
}
/*
// transmit nBytes from buffer out the uart
u08 uartSendBuffer(char *buffer, u16 nBytes)
{
register u08 first;
register u16 i;
// check if there's space (and that we have any bytes to send at all)
if((uartTxBuffer.datalength + nBytes < uartTxBuffer.size) && nBytes)
{
// grab first character
first = *buffer++;
// copy user buffer to uart transmit buffer
for(i = 0; i < nBytes-1; i++)
{
// put data bytes at end of buffer
bufferAddToEnd(&uartTxBuffer, *buffer++);
}
// send the first byte to get things going by interrupts
uartBufferedTx = TRUE;
uartSendByte(first);
// return success
return TRUE;
}
else
{
// return failure
return FALSE;
}
}
*/
// UART Transmit Complete Interrupt Handler
UART_INTERRUPT_HANDLER(USART_TXC_vect)
{
// check if buffered tx is enabled
if(uartBufferedTx)
{
// check if there's data left in the buffer
if(uartTxBuffer.datalength)
{
// send byte from top of buffer
outb(UDR, bufferGetFromFront(&uartTxBuffer));
}
else
{
// no data left
uartBufferedTx = FALSE;
// return to ready state
uartReadyTx = TRUE;
}
}
else
{
// we're using single-byte tx mode
// indicate transmit complete, back to ready
uartReadyTx = TRUE;
}
}
// UART Receive Complete Interrupt Handler
UART_INTERRUPT_HANDLER(USART_RXC_vect)
{
u08 c;
// get received char
c = inb(UDR);
// if there's a user function to handle this receive event
if(UartRxFunc)
{
// call it and pass the received data
UartRxFunc(c);
}
else
{
// otherwise do default processing
// put received char in buffer
// check if there's space
if( !bufferAddToEnd(&uartRxBuffer, c) )
{
// no space in buffer
// count overflow
uartRxOverflow++;
}
}
}