Lazuli
usart.c
Go to the documentation of this file.
1 /*
2  * SPDX-License-Identifier: GPL-3.0-only
3  * This file is part of Lazuli.
4  */
5 
14 #include <stdint.h>
15 #include <stdio.h>
16 
17 #include <Lazuli/common.h>
18 #include <Lazuli/config.h>
19 #include <Lazuli/serial.h>
21 #include <Lazuli/sys/arch/arch.h>
22 #include <Lazuli/sys/compiler.h>
23 #include <Lazuli/sys/kernel.h>
24 
28 static Usart * const usart = (Usart*)&UCSR0A;
29 
38 
39 int
40 putchar(int c)
41 {
42  const unsigned char value = (unsigned char)c;
43 
44  while (!(usart->ucsr0a & UCSR0A_UDRE0));
45 
46  usart->udr0 = value;
47 
48  return value;
49 }
50 
51 int
52 puts(const char * s)
53 {
54  const char newLine[] = LZ_CONFIG_SERIAL_NEWLINE;
55  uint8_t i;
56 
57  if (NULL == s) {
58  return EOF;
59  }
60 
61  while ('\0' != *s) {
62  putchar(*s);
63  s++;
64  }
65 
66  for (i = 0; i < sizeof(newLine) - 1; ++i) {
67  putchar(newLine[i]);
68  }
69 
70  return 1;
71 }
72 
78 static enum Lz_SerialEnableFlags
80 {
82 
83  if (usart->ucsr0b & UCSR0B_TXEN0) {
85  }
86 
87  if (usart->ucsr0b & UCSR0B_RXEN0) {
88  flags |= LZ_SERIAL_ENABLE_RECEIVE;
89  }
90 
91  return flags;
92 }
93 
99 static enum Lz_SerialStopBits
101 {
102  if (usart->ucsr0c & UCSR0C_USBS0) {
103  return LZ_SERIAL_STOP_BITS_2;
104  }
105 
106  return LZ_SERIAL_STOP_BITS_1;
107 }
108 
114 static enum Lz_SerialParityBit
116 {
117  if (usart->ucsr0c & UCSR0C_UPM01) {
118  if (usart->ucsr0c & UCSR0C_UPM00) {
119  return LZ_SERIAL_PARITY_ODD;
120  }
121 
122  return LZ_SERIAL_PARITY_EVEN;
123  }
124 
125  if (usart->ucsr0c & UCSR0C_UPM00) {
126  Kernel_Panic();
127  }
128 
129  return LZ_SERIAL_PARITY_NONE;
130 }
131 
137 static enum Lz_SerialSize
138 GetSize(void)
139 {
140  if (usart->ucsr0b & UCSR0B_UCSZ02) {
141  Kernel_Panic();
142  }
143 
144  if (usart->ucsr0c & UCSR0C_UCSZ01) {
145  if (usart->ucsr0c & UCSR0C_UCSZ00) {
146  return LZ_SERIAL_SIZE_8;
147  }
148 
149  return LZ_SERIAL_SIZE_7;
150  }
151 
152  if (usart->ucsr0c & UCSR0C_UCSZ00) {
153  return LZ_SERIAL_SIZE_6;
154  }
155 
156  return LZ_SERIAL_SIZE_5;
157 }
158 
164 static void
166 {
167  if (flags & LZ_SERIAL_ENABLE_TRANSMIT) {
168  usart->ucsr0b |= UCSR0B_TXEN0;
169  } else {
170  usart->ucsr0b &= ~UCSR0B_TXEN0;
171  }
172 
173  if (flags & LZ_SERIAL_ENABLE_RECEIVE) {
174  usart->ucsr0b |= UCSR0B_RXEN0;
175  } else {
176  usart->ucsr0b &= ~UCSR0B_RXEN0;
177  }
178 }
179 
183 static void
185 {
186  usart->ucsr0c &= ~UCSR0C_USBS0;
187 }
188 
192 static void
194 {
195  usart->ucsr0c |= UCSR0C_USBS0;
196 }
197 
204 PROGMEM static
205 void (* const setStopBits[])(void) = {
206  SetStopBits1,
207  SetStopBits2
208 };
209 
212 (
213  ELEMENTS_COUNT(setStopBits) == __LZ_SERIAL_STOP_BITS_ENUM_END,
214  all_entries_of_enum_Lz_SerialStopBits_must_be_set_in_setStopBits
215 );
223 static void
224 SetStopBits(const enum Lz_SerialStopBits stopBits)
225 {
226  void (*jump)(void);
227 
229  if (stopBits <= __LZ_SERIAL_STOP_BITS_ENUM_BEGIN ||
230  stopBits >= __LZ_SERIAL_STOP_BITS_ENUM_END) {
231  Kernel_Panic();
232  }
233  }
234 
236  jump();
237 }
238 
242 static void
244 {
245  usart->ucsr0c &= ~(UCSR0C_UPM01 | UCSR0C_UPM00);
246 }
247 
251 static void
253 {
254  usart->ucsr0c |= UCSR0C_UPM01;
255  usart->ucsr0c &= ~UCSR0C_UPM00;
256 }
257 
261 static void
263 {
264  usart->ucsr0c |= (UCSR0C_UPM01 | UCSR0C_UPM00);
265 }
266 
273 PROGMEM static
274 void (* const setParityBit[])(void) = {
278 };
279 
282 (
283  ELEMENTS_COUNT(setParityBit) == __LZ_SERIAL_PARITY_BIT_ENUM_END,
284  all_entries_of_enum_Lz_SerialParityBit_must_be_set_in_setParityBit
285 );
293 static void
294 SetParityBit(const enum Lz_SerialParityBit parityBit)
295 {
296  void (*jump)(void);
297 
299  if (parityBit <= __LZ_SERIAL_PARITY_BIT_ENUM_BEGIN ||
300  parityBit >= __LZ_SERIAL_PARITY_BIT_ENUM_END) {
301  Kernel_Panic();
302  }
303  }
304 
306  jump();
307 }
308 
312 static void
313 SetSize5(void)
314 {
315  usart->ucsr0b &= ~UCSR0B_UCSZ02;
316  usart->ucsr0c &= ~(UCSR0C_UCSZ01 | UCSR0C_UCSZ00);
317 }
318 
322 static void
323 SetSize6(void)
324 {
325  usart->ucsr0b &= ~UCSR0B_UCSZ02;
326  usart->ucsr0c &= ~UCSR0C_UCSZ01;
327  usart->ucsr0c |= UCSR0C_UCSZ00;
328 }
329 
333 static void
334 SetSize7(void)
335 {
336  usart->ucsr0b &= ~UCSR0B_UCSZ02;
337  usart->ucsr0c |= UCSR0C_UCSZ01;
338  usart->ucsr0c &= ~UCSR0C_UCSZ00;
339 }
340 
344 static void
345 SetSize8(void)
346 {
347  usart->ucsr0b &= ~UCSR0B_UCSZ02;
348  usart->ucsr0c |= (UCSR0C_UCSZ01 | UCSR0C_UCSZ00);
349 }
350 
356 PROGMEM static
357 void (* const setSize[])(void) = {
358  SetSize5,
359  SetSize6,
360  SetSize7,
361  SetSize8
362 };
363 
366 (
367  ELEMENTS_COUNT(setSize) == __LZ_SERIAL_SIZE_ENUM_END,
368  all_entries_of_enum_Lz_SerialSize_must_be_set_in_setSize
369 );
377 static void
378 SetSize(const enum Lz_SerialSize size)
379 {
380  void (* jump)(void);
381 
383  if (size <= __LZ_SERIAL_SIZE_ENUM_BEGIN ||
384  size >= __LZ_SERIAL_SIZE_ENUM_END) {
385  Kernel_Panic();
386  }
387  }
388 
390  jump();
391 }
392 
399 PROGMEM static const
401  (uint16_t)416,
402  (uint16_t)207,
403  (uint16_t)103,
404  (uint16_t)51
405 };
406 
409 (
410  ELEMENTS_COUNT(serialSpeedRegisterValue) == __LZ_SERIAL_SPEED_ENUM_END,
411  all_entries_of_enum_Lz_SerialSpeed_must_be_set_in_serialSpeedRegisterValue
412 );
420 static void
421 SetSpeed(const enum Lz_SerialSpeed speed)
422 {
423  uint16_t registerValue;
424 
426  if (speed <= __LZ_SERIAL_SPEED_ENUM_BEGIN ||
427  speed >= __LZ_SERIAL_SPEED_ENUM_END) {
428  Kernel_Panic();
429  }
430  }
431 
432  registerValue = Arch_LoadU16FromProgmem(&serialSpeedRegisterValue[speed]);
433 
434  usart->ubrr0l = LO8(registerValue);
435  usart->ubrr0h = HI8(registerValue);
436 
437  currentSerialSpeed = speed;
438 }
439 
440 void
442 {
443  configuration->enableFlags = GetEnablingStatus();
444  configuration->stopBits = GetStopBits();
445  configuration->parityBit = GetParityBit();
446  configuration->size = GetSize();
447  configuration->speed = currentSerialSpeed;
448 }
449 
450 void
452 {
453  InterruptsStatus interruptsStatus;
454 
455  /* Wait all receive and transmit operations has completed */
456  /* TODO: This one doesn't work as expected */
457  /* while (!(usart->ucsr0a & UCSR0A_TXC0) || (usart->ucsr0a & UCSR0A_RXC0)); */
458 
459  /*
460  * From the ATmega328p datasheet:
461  * "For interrupt driven USART operation, the Global Interrupt Flag should be
462  * cleared (and interrupts globally disabled) when doing the initialization."
463  */
465  interruptsStatus = Arch_DisableInterruptsGetStatus();
466  }
467 
468  SetEnablingStatus(configuration->enableFlags);
469  SetStopBits(configuration->stopBits);
470  SetParityBit(configuration->parityBit);
471  SetSize(configuration->size);
472  SetSpeed(configuration->speed);
473 
475  Arch_RestoreInterruptsStatus(interruptsStatus);
476  }
477 }
478 
479 void
481 {
482  const Lz_SerialConfiguration serialConfiguration = {
488  };
489 
490  Arch_SetSerialConfiguration(&serialConfiguration);
491 
492  /* Set USART to asynchronous */
494 }
volatile uint8_t ucsr0c
USART Control and Status Register C.
Definition: usart.h:52
uint8_t InterruptsStatus
Define the type used to store interrupts status.
Definition: arch.h:154
volatile uint8_t ucsr0b
USART Control and Status Register B.
Definition: usart.h:51
#define STATIC_ASSERT(C, M)
Perform an assertion at compile time.
Definition: common.h:63
Enable serial transmission.
Definition: serial.h:39
enum Lz_SerialStopBits stopBits
The number of stop bits.
Definition: serial.h:231
volatile uint8_t ubrr0l
USART Baud Rate Register low.
Definition: usart.h:54
enum Lz_SerialSize size
The size of the character.
Definition: serial.h:241
Use 6-bit character size on serial line.
Definition: serial.h:149
#define LO8(X)
Take the low byte of a 16-bit value.
Definition: common.h:213
static void SetParityBitEven(void)
Set even parity bit.
Definition: usart.c:252
Character Size 0.
Definition: usart.h:97
int putchar(int c)
Transmit a single character on the serial line.
Definition: usart.c:40
Use a 4800 baud rate on the serial line.
Definition: serial.h:194
enum Lz_SerialEnableFlags enableFlags
The enable/disable Tx/Rx options.
Definition: serial.h:226
static void SetSize5(void)
Set character size to 5 bits.
Definition: usart.c:313
Kernel symbols definition.
static void SetStopBits1(void)
Set USART to use 1 stop bit.
Definition: usart.c:184
static enum Lz_SerialEnableFlags GetEnablingStatus(void)
Retrieve the enabling status of the serial line.
Definition: usart.c:79
Describes the memory mapping for the USART.
Definition: usart.h:49
enum Lz_SerialParityBit parityBit
The kind of parity bit.
Definition: serial.h:236
static Usart *const usart
A constant pointer to the memory mapped Usart structure.
Definition: usart.c:28
static void SetParityBitNone(void)
Set no parity bit.
Definition: usart.c:243
static void SetSize7(void)
Set character size to 7 bits.
Definition: usart.c:334
static void(*const setSize[])(void)
Jump table to functions setting character sizes of the serial line.
Definition: usart.c:357
Include appropriate config file.
void Arch_InitSerial(void)
Initialize serial line with default configuration at system startup.
Definition: usart.c:480
Enable serial reception.
Definition: serial.h:44
#define EOF
Defines the End-Of-File constant.
Definition: stdio.h:24
static enum Lz_SerialStopBits GetStopBits(void)
Retrieve the number of stop bits currently used by the serial line.
Definition: usart.c:100
#define ELEMENTS_COUNT(X)
Get the number of elements in a statically initialized array.
Definition: common.h:278
enum Lz_SerialSpeed speed
The baud rate.
Definition: serial.h:246
Character size 1.
Definition: usart.h:96
static void SetStopBits(const enum Lz_SerialStopBits stopBits)
Set the number of stop bits of the serial line.
Definition: usart.c:224
USART Data Register Empty.
Definition: usart.h:65
static void SetSpeed(const enum Lz_SerialSpeed speed)
Set the baud rate of the serial line.
Definition: usart.c:421
Character Size 2.
Definition: usart.h:82
Macro aliases on compiler facilities.
static void SetSize6(void)
Set character size to 6 bits.
Definition: usart.c:323
InterruptsStatus Arch_DisableInterruptsGetStatus(void)
Disable all interrupts and return the previous interrupts status.
void Arch_RestoreInterruptsStatus(const InterruptsStatus interruptsStatus)
Restore a previously saved interrupts status.
Use 8-bit character size on serial line.
Definition: serial.h:159
Disable both serial transmission and reception.
Definition: serial.h:34
unsigned int uint16_t
Represents a unsigned integer type with width of exactly 16 bits.
Definition: stdint.h:94
volatile uint8_t ubrr0h
USART Baud Rate Register high.
Definition: usart.h:55
uint16_t Arch_LoadU16FromProgmem(const void *source)
Return a double-byte word stored in program memory.
static void SetStopBits2(void)
Set USART to use 2 stop bits.
Definition: usart.c:193
static void SetParityBit(const enum Lz_SerialParityBit parityBit)
Set the kind of parity bit of the serial line.
Definition: usart.c:294
static void(*const setStopBits[])(void)
Jump table to functions setting the number of stop bits of the serial line.
Definition: usart.c:205
volatile uint8_t ucsr0a
USART Control and Status Register A.
Definition: usart.h:50
Use 5-bit character size on serial line.
Definition: serial.h:144
Lz_SerialSize
Define the size of the character used on serial line.
Definition: serial.h:130
void(*)(void) Arch_LoadFunctionPointerFromProgmem(const void *source)
Return a function pointer stored in program memory.
Definition: arch.h:133
Serial port configuration interface.
#define UCSR0A
USART Control and Status Register A.
Definition: usart.h:29
void Kernel_Panic(void)
Kernel panic.
Definition: kernel.c:77
static enum Lz_SerialSize GetSize(void)
Retrieve the character size currently used by the serial line.
Definition: usart.c:138
#define LZ_CONFIG_SERIAL_NEWLINE
The sequence to use for new lines on the serial line.
Lz_SerialParityBit
Define the kind of parity bit to use on serial line.
Definition: serial.h:90
Use 2 stop bits.
Definition: serial.h:74
Lz_SerialEnableFlags
Define flags for enabling/disabling serial transmission/reception.
Definition: serial.h:30
Use no parity bit.
Definition: serial.h:104
Use 1 stop bit.
Definition: serial.h:69
USART Mode Select 1.
Definition: usart.h:91
unsigned char uint8_t
Represents a unsigned integer type with width of exactly 8 bits.
Definition: stdint.h:89
Use 7-bit character size on serial line.
Definition: serial.h:154
#define HI8(X)
Take the high byte of a 16-bit value.
Definition: common.h:220
static void SetSize(const enum Lz_SerialSize size)
Set the character size of the serial line.
Definition: usart.c:378
USART API for the ATmega328P.
Use even parity bit.
Definition: serial.h:109
#define NULL
NULL pointer.
Definition: common.h:68
Lz_SerialSpeed
Define the baud rate of the serial line.
Definition: serial.h:175
Use odd parity bit.
Definition: serial.h:114
int puts(const char *s)
Transmit the NUL-terminated string s followed by a trailing newline on the serial line...
Definition: usart.c:52
static void SetParityBitOdd(void)
Set odd parity bit.
Definition: usart.c:262
Receiver Enable.
Definition: usart.h:80
stdio standard header file.
volatile uint8_t udr0
USART I/O Data Register.
Definition: usart.h:56
static const uint16_t serialSpeedRegisterValue[]
Jump table containing the setting values of UBRR0L and UBRR0H registers for baud rates defined in Lz_...
Definition: usart.c:400
Represents the configuration of a serial interface.
Definition: serial.h:222
#define CLEAR_BITS(V, T, X)
Clear the corresponding bits of X in the value V of type T.
Definition: common.h:156
const bool LZ_CONFIG_CHECK_WRONG_ENUM_ENTRIES_IN_SERIAL
When 1, check for enum parameters that are over the admissible values defined by the enum...
Parity Mode 1.
Definition: usart.h:93
Lz_SerialStopBits
Define the number of stop bits to use on serial line.
Definition: serial.h:55
static enum Lz_SerialParityBit GetParityBit(void)
Retrieve the kind of parity currently used by the serial line.
Definition: usart.c:115
Basic type definitions and useful macros.
void Arch_SetSerialConfiguration(const Lz_SerialConfiguration *const configuration)
Configure the seria line according to the parameter.
Definition: usart.c:451
Architecture Abstraction API.
static void SetSize8(void)
Set character size to 8 bits.
Definition: usart.c:345
static void(*const setParityBit[])(void)
Jump table to functions setting the kind of parity of the serial line.
Definition: usart.c:274
Parity Mode 0.
Definition: usart.h:94
Transmitter Enable.
Definition: usart.h:81
Stop Bit Select.
Definition: usart.h:95
USART Mode Select 0.
Definition: usart.h:92
void Arch_GetSerialConfiguration(Lz_SerialConfiguration *const configuration)
Retrieve the current configuration of the serial line.
Definition: usart.c:441
const bool LZ_CONFIG_SERIAL_USE_INTERRUPTS
When 1, serial input and output will use interrupt blocking.
static enum Lz_SerialSpeed currentSerialSpeed
The current serial baud rate.
Definition: usart.c:37
static void SetEnablingStatus(const enum Lz_SerialEnableFlags flags)
Set the enabling/disabling of Tx/Rx of the serial line.
Definition: usart.c:165