-
Notifications
You must be signed in to change notification settings - Fork 0
/
serial.c
288 lines (263 loc) · 6.83 KB
/
serial.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
284
285
286
287
288
#include "stm32l011.h"
#include "serial.h"
// Serial comms routine for the stm32l011 mini nucleo board.
// makes use of usart2. Pins PA2 (tx) and PA15(rx) are used for transmission/reception
// Defines a new version of puts: e(mbedded)puts and egets
// Similar to puts and gets in standard C however egets checks the size
// of the input buffer. This could be extended to include a timeout quite easily.
// Written by Frank Duignan
//
// define the size of the communications buffer (adjust to suit)
#define MAXBUFFER 128
typedef struct tagComBuffer{
unsigned char Buffer[MAXBUFFER];
unsigned Head,Tail;
unsigned Count;
} ComBuffer;
ComBuffer ComRXBuffer,ComTXBuffer;
int PutBuf(ComBuffer *Buf,unsigned char Data);
unsigned char GetBuf(ComBuffer *Buf);
unsigned GetBufCount(ComBuffer *Buf);
int ReadCom(int Max,unsigned char *Buffer);
int WriteCom(int Count,unsigned char *Buffer);
void usart_tx (void);
void usart_rx (void);
unsigned ComOpen;
unsigned ComError;
unsigned ComBusy;
int ReadCom(int Max,unsigned char *Buffer)
{
// Read up to Max bytes from the communications buffer
// into Buffer. Return number of bytes read
unsigned i;
if (!ComOpen)
return (-1);
i=0;
while ((i < Max-1) && (GetBufCount(&ComRXBuffer)))
Buffer[i++] = GetBuf(&ComRXBuffer);
if (i>0)
{
Buffer[i]=0;
return(i);
}
else {
return(0);
}
};
int WriteCom(int Count,unsigned char *Buffer)
{
// Writes Count bytes from Buffer into the the communications TX buffer
// returns -1 if the port is not open (configured)
// returns -2 if the message is too big to be sent
// If the transmitter is idle it will initiate interrupts by
// writing the first character to the hardware transmit buffer
unsigned i,BufLen;
if (!ComOpen)
return (-1);
BufLen = GetBufCount(&ComTXBuffer);
if ( (MAXBUFFER - BufLen) < Count )
return (-2);
for(i=0;i<Count;i++)
PutBuf(&ComTXBuffer,Buffer[i]);
if ( (USART2_CR1 & BIT3)==0)
{ // transmitter was idle, turn it on and force out first character
USART2_CR1 |= BIT3;
USART2_TDR = GetBuf(&ComTXBuffer);
}
return 0;
};
void initUART(int BaudRate) {
int BaudRateDivisor;
disable_interrupts();
ComRXBuffer.Head = ComRXBuffer.Tail = ComRXBuffer.Count = 0;
ComTXBuffer.Head = ComTXBuffer.Tail = ComTXBuffer.Count = 0;
ComOpen = 1;
ComError = 0;
// Turn on the clock for GPIOA (usart 2 uses it) - not sure if I need this
RCC_IOPENR |= BIT0;
// Turn on the clock for the USART2 peripheral
RCC_APB1ENR |= BIT17;
// Configure the I/O pins. Will use PA2 as TX and PA15 as RX
GPIOA_MODER |= (BIT5 | BIT31);
GPIOA_MODER &= ~BIT4;
GPIOA_MODER &= ~BIT30;
// Turn on pull-ups to suppress noise when idle
GPIOA_PUPDR |= (BIT4 | BIT30);
GPIOA_PUPDR &= ~BIT5;
GPIOA_PUPDR &= ~BIT31;
// The alternate function number for PA2 and PA15 is AF4 (see datasheet, reference manual)
GPIOA_AFRL &= ~(BIT11 | BIT10 | BIT9 | BIT8);
GPIOA_AFRL |= BIT10;
GPIOA_AFRH &= ~(BIT31 | BIT30 | BIT29 | BIT28);
GPIOA_AFRH |= BIT30;
BaudRateDivisor = 16000000; // assuming 16MHz clock
BaudRateDivisor = BaudRateDivisor / (long) BaudRate;
// De-assert reset of USART2
RCC_APB1RSTR &= ~BIT17;
// Configure the USART
// disable USART first to allow setting of other control bits
// This also disables parity checking and enables 16 times oversampling
USART2_CR1 = 0;
// Don't want anything from CR2
USART2_CR2 = 0;
// Don't want anything from CR3
USART2_CR3 = 0;
// Set the baud rate
USART2_BRR = BaudRateDivisor;
// Turn on Transmitter, Receiver, Transmit and Receive interrupts.
USART2_CR1 |= (BIT2 | BIT5 | BIT6);
// Enable the USART
USART2_CR1 |= BIT0;
// Enable USART2 interrupts in NVIC
ISER |= BIT28;
// and enable interrupts
enable_interrupts();
}
void isr_usart2()
{
// check which interrupt happened.
if (USART2_ISR & BIT7) // is it a TXE interrupt?
usart_tx();
if (USART2_ISR & BIT5) // is it an RXNE interrupt?
usart_rx();
}
void usart_rx (void)
{
// Handles serial comms reception
// simply puts the data into the buffer and sets the ComError flag
// if the buffer is fullup
if (PutBuf(&ComRXBuffer,USART2_RDR) )
ComError = 1; // if PutBuf returns a non-zero value then there is an error
}
void usart_tx (void)
{
// Handles serial comms transmission
// When the transmitter is idle, this is called and the next byte
// is sent (if there is one)
if (GetBufCount(&ComTXBuffer))
USART2_TDR=GetBuf(&ComTXBuffer);
else
{
// No more data, disable the transmitter
USART2_CR1 &= ~BIT3;
if (USART2_ISR & BIT6)
// Write TCCF to USART_ICR
USART2_ICR |= BIT6;
if (USART2_ISR & BIT7)
// Write TXFRQ to USART_RQR
USART2_RQR |= BIT4;
}
}
int PutBuf(ComBuffer *Buf,unsigned char Data)
{
if ( (Buf->Head==Buf->Tail) && (Buf->Count!=0))
return(1); /* OverFlow */
disable_interrupts();
Buf->Buffer[Buf->Head++] = Data;
Buf->Count++;
if (Buf->Head==MAXBUFFER)
Buf->Head=0;
enable_interrupts();
return(0);
};
unsigned char GetBuf(ComBuffer *Buf)
{
unsigned char Data;
if ( Buf->Count==0 )
return (0);
disable_interrupts();
Data = Buf->Buffer[Buf->Tail++];
if (Buf->Tail == MAXBUFFER)
Buf->Tail = 0;
Buf->Count--;
enable_interrupts();
return (Data);
};
unsigned int GetBufCount(ComBuffer *Buf)
{
return Buf->Count;
};
int eputs(char *s)
{
// only writes to the comms port at the moment
if (!ComOpen)
return -1;
while (*s)
WriteCom(1,s++);
return 0;
}
int egets(char *s,int Max)
{
// read from the comms port until end of string
// or newline is encountered. Buffer is terminated with null
// returns number of characters read on success
// returns 0 or -1 if error occurs
// Warning: This is a blocking call.
int Len;
char c;
if (!ComOpen)
return -1;
Len=0;
c = 0;
while ( (Len < Max-1) && (c != NEWLINE) )
{
while (!GetBufCount(&ComRXBuffer)); // wait for a character
c = GetBuf(&ComRXBuffer);
s[Len++] = c;
}
if (Len>0)
{
s[Len]=0;
}
return Len;
}
char HexDigit(int Value)
{
if ((Value >=0) && (Value < 10))
return Value+'0';
else
return Value-10 + 'A';
}
void printHex(unsigned int Number)
{
// Output the number over the serial port as
// as hexadecimal string.
char TxString[9];
int Index=8;
TxString[Index]=0; // terminate the string
Index--;
while(Index >=0)
{
TxString[Index]=HexDigit(Number & 0x0f);
Number = Number >> 4;
Index--;
}
eputs(TxString);
}
int bytesAvailable(void)
{
return GetBufCount(&ComRXBuffer);
}
void printByte(uint8_t Number)
{
// Output the number over the serial port as
// as hexadecimal string.
char TxString[3];
int Index=2;
TxString[Index]=0; // terminate the string
Index--;
while(Index >=0)
{
TxString[Index]=HexDigit(Number & 0x0f);
Number = Number >> 4;
Index--;
}
eputs(TxString);
}
int TXIdle()
{
if ( (USART2_CR1 & BIT3)==0)
return 1;
else
return 0;
}