/* 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]; }