From 2dadbb8292def258db115195d4f2b20c1d779237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Thu, 14 Jun 2018 13:20:24 +0200 Subject: [PATCH] USART enhanced: add additional data bits and parity support --- lib/usart_enhanced.c | 185 +++++++++++++++++++++++++++++++++++++++++++ lib/usart_enhanced.h | 71 +++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 lib/usart_enhanced.c create mode 100644 lib/usart_enhanced.h diff --git a/lib/usart_enhanced.c b/lib/usart_enhanced.c new file mode 100644 index 0000000..efbcf36 --- /dev/null +++ b/lib/usart_enhanced.c @@ -0,0 +1,185 @@ +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +/** library for enhanced USART communication (code) + * @file usart_enhanced.c + * @author King Kévin + * @date 2018 + * @details the USART peripherals only support 8 or 9-bit word and even or odd parity (included in the data bits). The library adds support for 5 to 8-bit words, none/even/odd/mark/space parity (on top of the data bits) + * @note since parity is handled in software, the parity error (PE) flag is unused and should be replaced by the value return by usart_enhanced_parity_error + * @remark 9-bit raw communication is not supported since this is not common and can be done without this library + */ +/* standard libraries */ +#include // standard integer types + +/* STM32 (including CM3) libraries */ +#include // USART utilities + +/* own libraries */ +#include "usart_enhanced.h" // utilities for USART enhancements + +/** number of available USART peripherals */ +#define USART_PERIPHERALS_NB 3 +/** configured enhanced USART word size */ +static uint8_t usart_enhanced_databits[USART_PERIPHERALS_NB]; +/** configured enhanced USART parity */ +static enum usart_enhanced_parity_t usart_enhanced_parity[USART_PERIPHERALS_NB]; +/** last enhanced USART parity error status */ +static bool usart_enhanced_parity_errors[USART_PERIPHERALS_NB]; + +/** know if there is an even number of 1's in a integer + * @remark a look-up is a lot faster than making the calculation and doesn't does a lot of (flash) space + */ +static const bool even_parity_lut[256] = { true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, true, false, false, true, false, true, true, false, true, false, false, true, false, true, true, false, false, true, true, false, true, false, false, true, }; + + +/** get index of corresponding enhanced USART configurations + * @param[in] usart USART peripheral base address + * @return index used for the individual USART configurations + * @note the returned value is valid only is less than USART_PERIPHERALS_NB + */ +static uint8_t usart_enhanced_id(uint32_t usart) +{ + uint8_t to_return = USART_PERIPHERALS_NB; + switch (usart) { + case USART1: + to_return = 0; + break; + case USART2: + to_return = 1; + break; + case USART3: + to_return = 2; + break; + default: + to_return = USART_PERIPHERALS_NB; + break; + } + return to_return; +} + +bool usart_enhanced_config(uint32_t usart, uint8_t databits, enum usart_enhanced_parity_t parity) +{ + /* sanity check */ + uint8_t id = usart_enhanced_id(usart); + if (id>=USART_PERIPHERALS_NB) { + return false; + } + if (databits<5 || databits>8) { + return false; + } + if (parity>USART_ENHANCED_PARITY_SPACE) { + return false; + } + + // save configuration for later use + usart_enhanced_databits[id] = databits; + usart_enhanced_parity[id] = parity; + // configure USART peripheral + if (8==databits && USART_ENHANCED_PARITY_NONE!=parity) { // the parity bit is additional to the data bits + usart_set_databits(usart, 9); + } else { + usart_set_databits(usart, 8); + } + usart_set_parity(usart, USART_PARITY_NONE); // set no parity since we will take care of it ourselves + // we could also lower the number of stop bits when less than 8 bits are used, for higher throughput, but this is not a good idea since most UART transceiver parse 8 bits even is less is used + return true; +} + +void usart_enhanced_send(uint32_t usart, uint8_t data) +{ + /* sanity check */ + uint8_t id = usart_enhanced_id(usart); + if (id>=USART_PERIPHERALS_NB) { + return; + } + + data &= ~(0xff<=USART_PERIPHERALS_NB) { + return 0xff; + } + + uint16_t input = usart_recv(usart); // read received character (also clears the error flags) + input &= ~(0xffff<<(usart_enhanced_databits[id]+1)); // only keep the data bits + parity bit + // check the parity + uint16_t parity = input&(1<=USART_PERIPHERALS_NB) { + return false; + } + return usart_enhanced_parity_errors[id]; +} diff --git a/lib/usart_enhanced.h b/lib/usart_enhanced.h new file mode 100644 index 0000000..33f32c7 --- /dev/null +++ b/lib/usart_enhanced.h @@ -0,0 +1,71 @@ +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +/** library for enhanced USART communication (API) + * @file usart_enhanced.h + * @author King Kévin + * @date 2018 + * @details the USART peripherals only support 8 or 9-bit word and even or odd parity (included in the data bits). The library adds support for 5 to 8-bit words, none/even/odd/mark/space parity (on top of the data bits) + * @note since parity is handled in software, the parity error (PE) flag is unused and should be replaced by the value return by usart_enhanced_parity_error + * @remark 9-bit raw communication is not supported since this is not common and can be done without this library + */ +#pragma once + +/** enhanced USART setting for the additional parity bit*/ +enum usart_enhanced_parity_t { + /** no parity */ + USART_ENHANCED_PARITY_NONE, + /** even parity + * @note the number of 1's is even + */ + USART_ENHANCED_PARITY_EVEN, + /** odd parity + * @note the number of 1's is odd + */ + USART_ENHANCED_PARITY_ODD, + /** mark parity + * @note the parity bit is 1 + */ + USART_ENHANCED_PARITY_MARK, + /** space parity + * @note the parity bit is 0 + */ + USART_ENHANCED_PARITY_SPACE, +}; + +/** configure enhanced USART + * @param[in] usart USART peripheral base address + * @param[in] databits word size in bits (5 to 8) + * @param[in] parity additional parity bit + * @return if the input settings are valid and the configuration is successful + */ +bool usart_enhanced_config(uint32_t usart, uint8_t databits, enum usart_enhanced_parity_t parity); +/** send data over the enhanced USART using the configuration + * @param[in] usart USART peripheral base address + * @param[in] data data to be sent + * @note uses usart_send + */ +void usart_enhanced_send(uint32_t usart, uint8_t data); +/** receive data over the enhanced USART using the configuration + * @param[in] usart USART peripheral base address + * @return data received + * @note uses usart_recv + */ +uint8_t usart_enhanced_recv(uint32_t usart); +/** get the parity status of the received data + * @param[in] usart USART peripheral base address + * @return if there is a parity error + * @note the check only applies to the last data retrieved using usart_enhanced_recv + */ +bool usart_enhanced_parity_error(uint32_t usart);