USART enhanced: add additional data bits and parity support
This commit is contained in:
parent
dc389ceaeb
commit
ea28f20464
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/** library for enhanced USART communication (code)
|
||||
* @file usart_enhanced.c
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @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 <stdint.h> // standard integer types
|
||||
|
||||
/* STM32 (including CM3) libraries */
|
||||
#include <libopencm3/stm32/usart.h> // 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_enhanced_databits[id]); // only keep the data bits
|
||||
uint16_t output = data; // put value in output buffer
|
||||
switch (usart_enhanced_parity[id]) {
|
||||
case USART_ENHANCED_PARITY_NONE: // a mark is also decoded as idle/stop
|
||||
case USART_ENHANCED_PARITY_MARK:
|
||||
output |= (1<<usart_enhanced_databits[id]); // add idle state
|
||||
break;
|
||||
case USART_ENHANCED_PARITY_EVEN:
|
||||
if (!even_parity_lut[data]) {
|
||||
output |= (1<<usart_enhanced_databits[id]);
|
||||
}
|
||||
// no need to clear a bit if the parity is even
|
||||
break;
|
||||
case USART_ENHANCED_PARITY_ODD:
|
||||
if (even_parity_lut[data]) {
|
||||
output |= (1<<usart_enhanced_databits[id]);
|
||||
}
|
||||
// no need to clear a bit if the parity is odd
|
||||
break;
|
||||
case USART_ENHANCED_PARITY_SPACE:
|
||||
// no need to clear the bit
|
||||
break;
|
||||
}
|
||||
output |= (0xffff<<(usart_enhanced_databits[id]+1)); // set additional bits to idle (high)
|
||||
usart_send(usart, output); // transmit character
|
||||
}
|
||||
|
||||
uint8_t usart_enhanced_recv(uint32_t usart)
|
||||
{
|
||||
/* sanity check */
|
||||
uint8_t id = usart_enhanced_id(usart);
|
||||
if (id>=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_enhanced_databits[id]); // only keep the parity bit
|
||||
usart_enhanced_parity_errors[id] = false;
|
||||
switch (usart_enhanced_parity[id]) {
|
||||
case USART_ENHANCED_PARITY_NONE:
|
||||
usart_enhanced_parity_errors[id] = false;
|
||||
break;
|
||||
case USART_ENHANCED_PARITY_EVEN:
|
||||
if (parity) {
|
||||
usart_enhanced_parity_errors[id] = !even_parity_lut[input&0xff];
|
||||
} else {
|
||||
usart_enhanced_parity_errors[id] = even_parity_lut[input&0xff];
|
||||
}
|
||||
break;
|
||||
case USART_ENHANCED_PARITY_ODD:
|
||||
if (parity) {
|
||||
usart_enhanced_parity_errors[id] = even_parity_lut[input&0xff];
|
||||
} else {
|
||||
usart_enhanced_parity_errors[id] = !even_parity_lut[input&0xff];
|
||||
}
|
||||
break;
|
||||
case USART_ENHANCED_PARITY_MARK:
|
||||
usart_enhanced_parity_errors[id] = !parity;
|
||||
break;
|
||||
case USART_ENHANCED_PARITY_SPACE:
|
||||
usart_enhanced_parity_errors[id] = parity;
|
||||
break;
|
||||
}
|
||||
input &= ~(0xffff<<(usart_enhanced_databits[id])); // only keep the data bits
|
||||
return input;
|
||||
}
|
||||
|
||||
bool usart_enhanced_parity_error(uint32_t usart)
|
||||
{
|
||||
/* sanity check */
|
||||
uint8_t id = usart_enhanced_id(usart);
|
||||
if (id>=USART_PERIPHERALS_NB) {
|
||||
return false;
|
||||
}
|
||||
return usart_enhanced_parity_errors[id];
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
/** library for enhanced USART communication (API)
|
||||
* @file usart_enhanced.h
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @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);
|
Loading…
Reference in New Issue