Skip to content

Commit dbf3f39

Browse files
authored
Feature STM8 Soft UART support (#58)
* Add Software UART support for STM8 and refactor UART configuration * Refactor soft UART implementation for STM8: update pin handling and add delay function * Fix comments
1 parent 34dac0f commit dbf3f39

6 files changed

Lines changed: 123 additions & 50 deletions

File tree

c/l4/README.md

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@ Initial value for CRC16 calculation.
1616
Default: `0xFFFF`.
1717
Used as the starting point for CRC16 calculation.
1818

19-
## `V2STYXLIB_STREAMING_MODE`
20-
Flag bit indicating streaming mode is enabled.
21-
Default: `0x01`.
22-
When set, UART operates in streaming mode:
23-
- SOF (Start of Frame) markers are sent before each data frame.
24-
- The sender does not wait for responses between transmissions.
25-
2619
## `V2STYXLIB_SOF_MARKER_1`
2720
First byte of the Start of Frame (SOF) marker sequence.
2821
Default: `0x55`.
@@ -33,10 +26,10 @@ Second byte of the Start of Frame (SOF) marker sequence.
3326
Default: `0xAA`.
3427
Used with `V2STYXLIB_SOF_MARKER_1` to form the two-byte SOF marker sequence: `0x55 0xAA`.
3528

36-
## `V2STYXLIB_SEND_CRC16`
37-
Flag bit indicating CRC16 is appended to each transmitted frame.
38-
Default: `0x02`.
39-
When set, a 2-byte CRC16 checksum (using `V2STYXLIB_CRC16_POLY` and
40-
`V2STYXLIB_CRC16_INITIAL_VALUE`) is added at the beggining of every frame,
41-
before the payload.
42-
This extends the frame layout by two bytes and enables end-to-end error detection.
29+
## `V2STYXLIB_SOFTUART_TX`
30+
31+
Enables the use of Software UART for TX on STM8. This is particularly useful when
32+
you need additional ADC channels and want to free up the **UART1_TX / AIN5 / (HS) PD5** pin for analog input.
33+
34+
**Note:** This implementation covers TX only, as software-based RX is generally
35+
unstable on this architecture due to timing constraints.

c/l4/include/ChannelUartStm8.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55

66
#include "Channel_c.h"
77

8+
typedef struct {
9+
V2styxlibUartConfig baseConfig;
10+
#ifdef V2STYXLIB_SOFTUART
11+
GPIO_TypeDef * softUartPort;
12+
uint8_t softUartTxPinMask;
13+
#endif
14+
} V2styxlibUartStm8Config;
15+
816
/**
917
* baudRateDivider - is a value that determines the data transmission speed over UART.
1018
* It is calculated based on the clock frequency (F_CPU) and the desired transmission speed (baud rate).
@@ -14,15 +22,18 @@
1422
* baudRateDivider = 16000000 / 115200 ≈ 138.89
1523
* In this case, baudRateDivider will be approximately 139 (rounded to the nearest integer).
1624
*/
17-
void v2styxlib_uart_setup(uint16_t baudRateDivider);
25+
void v2styxlib_uart_setup(
26+
const V2styxlibUartStm8Config* config,
27+
uint16_t baudRateDivider
28+
);
1829

1930
/**
2031
* buffer - is a pointer to the data buffer that contains the data to be sent over UART.
2132
* length - is the number of bytes to be sent from the buffer.
2233
* This function is responsible for sending a specified number of bytes from the provided buffer over UART.
2334
*/
2435
void v2styxlib_uart_send(
25-
const V2styxlibUartConfig* config,
36+
const V2styxlibUartStm8Config* config,
2637
const uint8_t *buffer,
2738
BufferSize_t length
28-
);
39+
);

c/l4/include/Channel_c.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,9 @@
1414
#define V2STYXLIB_CRC16_INITIAL_VALUE 0xFFFF
1515
#endif
1616

17-
#ifndef V2STYXLIB_STREAMING_MODE
18-
#define V2STYXLIB_STREAMING_MODE 0x01
19-
#endif
20-
#ifndef V2STYXLIB_SEND_CRC16
21-
#define V2STYXLIB_SEND_CRC16 0x02
22-
#endif
17+
#define V2STYXLIB_CONFIG_STREAMING_MODE 0x01
18+
#define V2STYXLIB_CONFIG_SEND_CRC16 0x02
19+
#define V2STYXLIB_CONFIG_SOFT_UART_TX 0x04
2320

2421
#ifndef V2STYXLIB_SOF_MARKER_1
2522
#define V2STYXLIB_SOF_MARKER_1 0x55
@@ -31,7 +28,7 @@ extern "C" {
3128
#endif
3229

3330
typedef struct {
34-
uint8_t config;
31+
uint8_t config;
3532
} V2styxlibUartConfig;
3633

3734
/**
@@ -43,11 +40,15 @@ typedef struct {
4340
*
4441
* sendCrc16 - is a boolean flag that indicates whether to calculate and send
4542
* CRC16 checksum with each message.
43+
*
44+
* useSoftUartTx - is a boolean flag that indicates whether to use software
45+
* UART for transmission.
4646
*/
4747
void v2styxlib_uart_configure_proto(
4848
V2styxlibUartConfig *config,
4949
bool useStreamingMode,
50-
bool sendCrc16
50+
bool sendCrc16,
51+
bool useSoftUartTx
5152
);
5253

5354
/**

c/l4/library.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "1.0.0",
44
"build": {
55
"srcFilter": [
6+
"+<Channel_c.c>",
67
"+<ChannelUartStm8.c>"
78
]
89
}

c/l4/src/ChannelUartStm8.c

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,107 @@
11
#include "ChannelUartStm8.h"
22

3-
#define WAIT_FOR_TXE() while (!(UART1->SR & UART1_SR_TXE))
3+
#ifdef V2STYXLIB_SOFTUART
4+
static void v2styxlib_delay_bit() {
5+
__asm
6+
pushw x
7+
ldw x, #535 ; hardcode for 9600 baud at 16 MHz, adjust if needed
8+
00001$:
9+
decw x
10+
jrne 00001$
11+
popw x
12+
__endasm;
13+
}
14+
#endif
15+
16+
static void v2styxlib_send_byte(
17+
const V2styxlibUartStm8Config* config,
18+
uint8_t byte) {
19+
#ifdef V2STYXLIB_SOFTUART
20+
if (config->baseConfig.config & V2STYXLIB_CONFIG_SOFT_UART_TX) {
21+
// Send byte using software UART
22+
// Start bit
23+
__asm
24+
sim ; disable interrupts (software UART timing)
25+
__endasm;
26+
config->softUartPort->ODR &= ~config->softUartTxPinMask;
27+
v2styxlib_delay_bit();
28+
29+
// Data bits (LSB first)
30+
for (uint8_t i = 0; i < 8; i++) {
31+
if (byte & 0x01) {
32+
config->softUartPort->ODR |= config->softUartTxPinMask;
33+
} else {
34+
config->softUartPort->ODR &= ~config->softUartTxPinMask;
35+
}
36+
byte >>= 1;
37+
v2styxlib_delay_bit();
38+
}
439

5-
void v2styxlib_uart_setup(uint16_t baudRateDivider)
40+
// Stop bit
41+
config->softUartPort->ODR |= config->softUartTxPinMask;
42+
v2styxlib_delay_bit();
43+
__asm
44+
rim ; enable interrupts (software UART timing)
45+
__endasm;
46+
} else
47+
#endif
48+
{
49+
while (!(UART1->SR & UART1_SR_TXE)) {
50+
51+
};
52+
UART1->DR = byte;
53+
}
54+
}
55+
56+
void v2styxlib_uart_setup(
57+
const V2styxlibUartStm8Config* config,
58+
uint16_t baudRateDivider)
659
{
60+
UART1->CR1 |= UART1_CR1_UARTD; // Disable UART before configuration
761
UART1->BRR2 = ((baudRateDivider >> 8) & 0xF0) | (baudRateDivider & 0x0F);
862
UART1->BRR1 = (baudRateDivider >> 4) & 0xFF;
9-
UART1->CR2 |= UART1_CR2_TEN;
63+
#ifdef V2STYXLIB_SOFTUART
64+
if (config->baseConfig.config & V2STYXLIB_CONFIG_SOFT_UART_TX) {
65+
// Configure the soft UART TX pin as output
66+
config->softUartPort->DDR |= config->softUartTxPinMask;
67+
config->softUartPort->CR1 |= config->softUartTxPinMask;
68+
config->softUartPort->CR2 |= config->softUartTxPinMask;
69+
config->softUartPort->ODR |= config->softUartTxPinMask;
70+
UART1->CR2 &= ~UART1_CR2_TEN; // Disable hardware UART transmission, we will use software UART for TX
71+
UART1->CR2 |= UART1_CR2_REN;
72+
} else
73+
#endif
74+
{
75+
UART1->CR2 |= (UART1_CR2_TEN | UART1_CR2_REN);
76+
}
77+
UART1->CR1 &= ~UART1_CR1_UARTD; // Enable UART after configuration
1078
}
1179

1280
void v2styxlib_uart_send(
13-
const V2styxlibUartConfig* config,
81+
const V2styxlibUartStm8Config* config,
1482
const uint8_t *buffer,
1583
BufferSize_t length)
1684
{
17-
if (config->config & V2STYXLIB_STREAMING_MODE) {
85+
if (config->baseConfig.config & V2STYXLIB_CONFIG_STREAMING_MODE) {
1886
// If streaming mode is enabled, send SOF markers before the data
19-
WAIT_FOR_TXE();
20-
UART1->DR = V2STYXLIB_SOF_MARKER_1;
21-
22-
WAIT_FOR_TXE();
23-
UART1->DR = V2STYXLIB_SOF_MARKER_2;
87+
v2styxlib_send_byte(config, V2STYXLIB_SOF_MARKER_1);
88+
v2styxlib_send_byte(config, V2STYXLIB_SOF_MARKER_2);
2489
}
2590

26-
WAIT_FOR_TXE();
27-
if (config->config & V2STYXLIB_SEND_CRC16) {
91+
if (config->baseConfig.config & V2STYXLIB_CONFIG_SEND_CRC16) {
2892
// send packet size + 2 bytes for CRC16
29-
UART1->DR = length + 2;
93+
v2styxlib_send_byte(config, length + 2);
3094
// then CRC16
3195
uint16_t crc = v2styxlib_crc16_calculate(buffer, length);
32-
WAIT_FOR_TXE();
33-
UART1->DR = (crc >> 8) & 0xFF; // send high byte of CRC
34-
WAIT_FOR_TXE();
35-
UART1->DR = crc & 0xFF; // send low byte of CRC
96+
v2styxlib_send_byte(config, (crc >> 8) & 0xFF); // send high byte of CRC
97+
v2styxlib_send_byte(config, crc & 0xFF); // send low byte of CRC
3698
} else {
3799
// send packet size
38-
UART1->DR = length;
100+
v2styxlib_send_byte(config, length);
39101
}
40102

41103
// then send the actual data
42104
for (BufferSize_t i = 0; i < length; i++) {
43-
WAIT_FOR_TXE();
44-
UART1->DR = buffer[i];
105+
v2styxlib_send_byte(config, buffer[i]);
45106
}
46107
}

c/l4/src/Channel_c.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,22 @@ uint16_t v2styxlib_crc16_calculate(const uint8_t *data, BufferSize_t length) {
2323
void v2styxlib_uart_configure_proto(
2424
V2styxlibUartConfig *config,
2525
bool useStreamingMode,
26-
bool sendCrc16
26+
bool sendCrc16,
27+
bool useSoftUartTx
2728
) {
2829
if (useStreamingMode) {
29-
config->config |= V2STYXLIB_STREAMING_MODE;
30+
config->config |= V2STYXLIB_CONFIG_STREAMING_MODE;
3031
} else {
31-
config->config &= ~V2STYXLIB_STREAMING_MODE;
32+
config->config &= ~V2STYXLIB_CONFIG_STREAMING_MODE;
3233
}
3334
if (sendCrc16) {
34-
config->config |= V2STYXLIB_SEND_CRC16;
35+
config->config |= V2STYXLIB_CONFIG_SEND_CRC16;
3536
} else {
36-
config->config &= ~V2STYXLIB_SEND_CRC16;
37+
config->config &= ~V2STYXLIB_CONFIG_SEND_CRC16;
38+
}
39+
if (useSoftUartTx) {
40+
config->config |= V2STYXLIB_CONFIG_SOFT_UART_TX;
41+
} else {
42+
config->config &= ~V2STYXLIB_CONFIG_SOFT_UART_TX;
3743
}
3844
}

0 commit comments

Comments
 (0)