Porting guide¶
Implement low-level driver¶
Implementation of low-level driver is an essential part. It links middleware with actual hardware design of the device.
Its implementation must provide 4
functions:
To open/configure UART hardware
To set UART baudrate on the fly
To transmit/receive data over UART
To close/de-init UART hardware
After these functions have been implemented (check below for references),
driver must link these functions to single driver structure of type lwow_ll_drv_t
,
later used during instance initialization.
Tip
Check Low-level driver for function prototypes.
Implement system functions¶
System functions are required only if operating system mode is enabled, with LWOW_CFG_OS
.
Its implementation structure is not the same as for low-level driver,
customer needs to implement fixed functions, with pre-defined name, starting with ow_sys_
name.
System function must only support OS mutex management and has to provide:
ow_sys_mutex_create()
function to create new mutexow_sys_mutex_delete()
function to delete existing mutexow_sys_mutex_wait()
function to wait for mutex to be availableow_sys_mutex_release()
function to release (give) mutex back
Warning
Application must define LWOW_CFG_OS_MUTEX_HANDLE
for mutex type.
This shall be done in lwow_opts.h
file.
Tip
Check System functions for function prototypes.
Example: Low-level driver for WIN32¶
Example code for low-level porting on WIN32 platform. It uses native Windows features to open COM port and read/write from/to it.
1/**
2 * \file lwow_ll_win32.c
3 * \brief UART implementation for WIN32
4 */
5
6/*
7 * Copyright (c) 2020 Tilen MAJERLE
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * This file is part of LwOW - Lightweight onewire library.
30 *
31 * Author: Tilen MAJERLE <tilen@majerle.eu>
32 * Version: v3.0.2
33 */
34#include <stdio.h>
35#include "lwow/lwow.h"
36#include "windows.h"
37
38#if !__DOXYGEN__
39
40/* Function prototypes */
41static uint8_t init(void* arg);
42static uint8_t deinit(void* arg);
43static uint8_t set_baudrate(uint32_t baud, void* arg);
44static uint8_t transmit_receive(const uint8_t* tx, uint8_t* rx, size_t len, void* arg);
45
46/* Win 32 LL driver for OW */
47const lwow_ll_drv_t
48lwow_ll_drv_win32 = {
49 .init = init,
50 .deinit = deinit,
51 .set_baudrate = set_baudrate,
52 .tx_rx = transmit_receive,
53};
54
55static HANDLE com_port;
56static DCB dcb = { 0 };
57
58static uint8_t
59init(void* arg) {
60 dcb.DCBlength = sizeof(dcb);
61
62 /* Open virtual file as read/write */
63 com_port = CreateFile(L"\\\\.\\COM4",
64 GENERIC_READ | GENERIC_WRITE,
65 0,
66 0,
67 OPEN_EXISTING,
68 0,
69 NULL
70 );
71
72 /* First read current values */
73 if (GetCommState(com_port, &dcb)) {
74 COMMTIMEOUTS timeouts;
75
76 dcb.BaudRate = 115200;
77 dcb.ByteSize = 8;
78 dcb.Parity = NOPARITY;
79 dcb.StopBits = ONESTOPBIT;
80
81 /* Try to set com port data */
82 if (!SetCommState(com_port, &dcb)) {
83 printf("Cannot get COM port\r\n");
84 return 0;
85 }
86
87 if (GetCommTimeouts(com_port, &timeouts)) {
88 /* Set timeout to return immediatelly from ReadFile function */
89 timeouts.ReadIntervalTimeout = MAXDWORD;
90 timeouts.ReadTotalTimeoutConstant = 0;
91 timeouts.ReadTotalTimeoutMultiplier = 0;
92 if (!SetCommTimeouts(com_port, &timeouts)) {
93 printf("Cannot set COM PORT timeouts\r\n");
94 }
95 GetCommTimeouts(com_port, &timeouts);
96 }
97 } else {
98 printf("Cannot get COM port info\r\n");
99 }
100
101 return 1;
102}
103
104uint8_t
105deinit(void* arg) {
106 /* Disable UART peripheral */
107
108 return 1;
109}
110
111uint8_t
112set_baudrate(uint32_t baud, void* arg) {
113 /* Configure UART to selected baudrate */
114 dcb.BaudRate = baud;
115
116 /* Try to set com port data */
117 if (!SetCommState(com_port, &dcb)) {
118 printf("Cannot set COM port baudrate to %u bauds\r\n", (unsigned)baud);
119 return 0;
120 }
121
122 return 1;
123}
124
125uint8_t
126transmit_receive(const uint8_t* tx, uint8_t* rx, size_t len, void* arg) {
127 /* Perform data exchange */
128 size_t read = 0;
129 DWORD br;
130
131 if (com_port != NULL) {
132 /*
133 * Flush any data in RX buffer.
134 * This helps to reset communication in case of on-the-fly device management
135 * if one-or-more device(s) are added or removed.
136 *
137 * Any noise on UART level could start byte and put it to Win buffer,
138 * preventing to read aligned data from it
139 */
140 PurgeComm(com_port, PURGE_RXCLEAR | PURGE_RXABORT);
141
142 /* Write file and send data */
143 WriteFile(com_port, tx, len, &br, NULL);
144 FlushFileBuffers(com_port);
145
146 /* Read same amount of data as sent previously (loopback) */
147 do {
148 if (ReadFile(com_port, rx, (DWORD)(len - read), &br, NULL)) {
149 read += (size_t)br;
150 rx += (size_t)br;
151 }
152 } while (read < len);
153 }
154
155 return 1;
156}
157
158#endif /* !__DOXYGEN__ */
Example: Low-level driver for STM32¶
Example code for low-level porting on STM32 platform.
1/**
2 * \file lwow_ll_stm32.c
3 * \brief Generic UART implementation for STM32 MCUs
4 */
5
6/*
7 * Copyright (c) 2020 Tilen MAJERLE
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * This file is part of LwOW - Lightweight onewire library.
30 *
31 * Author: Tilen MAJERLE <tilen@majerle.eu>
32 * Version: v3.0.2
33 */
34
35/*
36 * How it works
37 *
38 * https://docs.majerle.eu/projects/lwow/en/latest/user-manual/hw_connection.html#
39 */
40#include "lwow/lwow.h"
41
42#if !__DOXYGEN__
43
44static uint8_t init(void* arg);
45static uint8_t deinit(void* arg);
46static uint8_t set_baudrate(uint32_t baud, void* arg);
47static uint8_t transmit_receive(const uint8_t* tx, uint8_t* rx, size_t len, void* arg);
48
49/* STM32 LL driver for OW */
50const lwow_ll_drv_t
51lwow_ll_drv_stm32 = {
52 .init = init,
53 .deinit = deinit,
54 .set_baudrate = set_baudrate,
55 .tx_rx = transmit_receive,
56};
57
58static LL_USART_InitTypeDef
59usart_init;
60
61static uint8_t
62init(void* arg) {
63 LL_GPIO_InitTypeDef gpio_init;
64
65 /* Peripheral clock enable */
66 ONEWIRE_USART_CLK_EN;
67 ONEWIRE_TX_PORT_CLK_EN;
68 ONEWIRE_RX_PORT_CLK_EN;
69
70 /* Configure GPIO pins */
71 LL_GPIO_StructInit(&gpio_init);
72 gpio_init.Mode = LL_GPIO_MODE_ALTERNATE;
73 gpio_init.Speed = LL_GPIO_SPEED_FREQ_HIGH;
74 gpio_init.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
75 gpio_init.Pull = LL_GPIO_PULL_UP;
76
77 /* TX pin */
78 gpio_init.Alternate = ONEWIRE_TX_PIN_AF;
79 gpio_init.Pin = ONEWIRE_TX_PIN;
80 LL_GPIO_Init(ONEWIRE_TX_PORT, &gpio_init);
81
82 /* RX pin */
83 gpio_init.Alternate = ONEWIRE_RX_PIN_AF;
84 gpio_init.Pin = ONEWIRE_RX_PIN;
85 LL_GPIO_Init(ONEWIRE_RX_PORT, &gpio_init);
86
87 /* Configure UART peripherals */
88 LL_USART_DeInit(ONEWIRE_USART);
89 LL_USART_StructInit(&usart_init);
90 usart_init.BaudRate = 9600;
91 usart_init.DataWidth = LL_USART_DATAWIDTH_8B;
92 usart_init.StopBits = LL_USART_STOPBITS_1;
93 usart_init.Parity = LL_USART_PARITY_NONE;
94 usart_init.TransferDirection = LL_USART_DIRECTION_TX_RX;
95 usart_init.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
96 usart_init.OverSampling = LL_USART_OVERSAMPLING_16;
97 LL_USART_Init(ONEWIRE_USART, &usart_init);
98 LL_USART_ConfigAsyncMode(ONEWIRE_USART);
99
100 LWOW_UNUSED(arg);
101
102 return 1;
103}
104
105static uint8_t
106deinit(void* arg) {
107 LL_USART_DeInit(ONEWIRE_USART);
108 LWOW_UNUSED(arg);
109 return 1;
110}
111
112static uint8_t
113set_baudrate(uint32_t baud, void* arg) {
114 usart_init.BaudRate = baud;
115 LL_USART_Init(ONEWIRE_USART, &usart_init);
116 LL_USART_ConfigAsyncMode(ONEWIRE_USART);
117 LWOW_UNUSED(arg);
118
119 return 1;
120}
121
122static uint8_t
123transmit_receive(const uint8_t* tx, uint8_t* rx, size_t len, void* arg) {
124 const uint8_t* t = tx;
125 uint8_t* r = rx;
126
127 /* Send byte with polling */
128 LL_USART_Enable(ONEWIRE_USART);
129 for (; len > 0; --len, ++t, ++r) {
130 LL_USART_TransmitData8(ONEWIRE_USART, *t);
131 while (!LL_USART_IsActiveFlag_TXE(ONEWIRE_USART));
132 while (!LL_USART_IsActiveFlag_RXNE(ONEWIRE_USART));
133 *r = LL_USART_ReceiveData8(ONEWIRE_USART);
134 }
135 while (!LL_USART_IsActiveFlag_TC(ONEWIRE_USART)) {}
136 LL_USART_Disable(ONEWIRE_USART);
137 LWOW_UNUSED(arg);
138 return 1;
139}
140
141#endif /* !__DOXYGEN__ */
Example: System functions for WIN32¶
1/**
2 * \file lwow_sys_win32.c
3 * \brief System functions for WIN32
4 */
5
6/*
7 * Copyright (c) 2020 Tilen MAJERLE
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * This file is part of LwOW - Lightweight onewire library.
30 *
31 * Author: Tilen MAJERLE <tilen@majerle.eu>
32 * Version: v3.0.2
33 */
34#include "lwow/lwow.h"
35#include "windows.h"
36
37#if LWOW_CFG_OS && !__DOXYGEN__
38
39uint8_t
40lwow_sys_mutex_create(LWOW_CFG_OS_MUTEX_HANDLE* mutex, void* arg) {
41 *mutex = CreateMutex(NULL, 0, NULL);
42 return 1;
43}
44
45uint8_t
46lwow_sys_mutex_delete(LWOW_CFG_OS_MUTEX_HANDLE* mutex, void* arg) {
47 CloseHandle(*mutex);
48 *mutex = NULL;
49 return 1;
50}
51
52uint8_t
53lwow_sys_mutex_wait(LWOW_CFG_OS_MUTEX_HANDLE* mutex, void* arg) {
54 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0;
55}
56
57uint8_t
58lwow_sys_mutex_release(LWOW_CFG_OS_MUTEX_HANDLE* mutex, void* arg) {
59 return ReleaseMutex(*mutex);
60}
61
62#endif /* LWOW_CFG_OS && !__DOXYGEN__ */
Example: System functions for CMSIS-OS¶
1/**
2 * \file lwow_sys_cmsis_os.c
3 * \brief System functions for CMSIS-OS based operating system
4 */
5
6/*
7 * Copyright (c) 2020 Tilen MAJERLE
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * This file is part of LwOW - Lightweight onewire library.
30 *
31 * Author: Tilen MAJERLE <tilen@majerle.eu>
32 * Version: v3.0.2
33 */
34#include "lwow/lwow.h"
35
36#if LWOW_CFG_OS && !__DOXYGEN__
37
38#include "cmsis_os.h"
39
40uint8_t
41lwow_sys_mutex_create(LWOW_CFG_OS_MUTEX_HANDLE* m, void* arg) {
42 LWOW_UNUSED(arg);
43 const osMutexAttr_t attr = {
44 .attr_bits = osMutexRecursive,
45 .name = "lwow_mutex",
46 };
47 return (*m = osMutexNew(&attr)) != NULL;
48}
49
50uint8_t
51lwow_sys_mutex_delete(LWOW_CFG_OS_MUTEX_HANDLE* m, void* arg) {
52 LWOW_UNUSED(arg);
53 return osMutexDelete(*m) == osOK;
54}
55
56uint8_t
57lwow_sys_mutex_wait(LWOW_CFG_OS_MUTEX_HANDLE* m, void* arg) {
58 LWOW_UNUSED(arg);
59 return osMutexAcquire(*m, osWaitForever) == osOK;
60}
61
62uint8_t
63lwow_sys_mutex_release(LWOW_CFG_OS_MUTEX_HANDLE* m, void* arg) {
64 LWOW_UNUSED(arg);
65 return osMutexRelease(*m) == osOK;
66}
67
68#endif /* LWOW_CFG_OS && !__DOXYGEN__ */
Low-Level driver for STM32 with STM32CubeMX¶
Specific low-level driver has been implemented for STM32 series of microcontrollers, to allow easy and simple link of LwOW library with projects generated with STM32CubeMX or STm32CubeIDE development tools.
Driver is based on HAL (Hardware Abstraction Layer) and it uses interrupt configuration to transmit/receive data. When customer starts a new project using CubeMX, it must:
Configure specific UART IP as async mode both directions
UART must have enabled global interrupts, to allow transmitting/receiving data using interrupts
Application must pass pointer to UART handle when calling
ow_init
function
Tip
Special example has been developed to demonstrate how can application use
multiple OneWire instances on multiple UART ports at the same time.
It uses custom argument to determine which UART handle shall be used for data transmit.
Check /examples/stm32/
folder for actual implementation.
1/**
2 * \file lwow_ll_stm32_hal.c
3 * \brief UART driver implementation for STM32 with HAL code
4 */
5
6/*
7 * Copyright (c) 2020 Tilen MAJERLE
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * This file is part of LwOW - Lightweight onewire library.
30 *
31 * Author: Tilen MAJERLE <tilen@majerle.eu>
32 * Version: v3.0.2
33 */
34
35/*
36 * How it works (general)
37 *
38 * https://docs.majerle.eu/projects/lwow/en/latest/user-manual/hw_connection.html#
39 *
40 * This specific driver is optimized for proejcts generated by STM32CubeMX or STM32CubeIDE with HAL drivers
41 * It can be used w/ or w/o operating system and it uses interrupts & polling for data receive and data transmit.
42 *
43 * Application must pass pointer to UART handle as argument to ow_init function in order
44 * to link OW instance with actual UART hardware used for OW instance.
45 *
46 * To use this driver, application must:
47 * - Enable interrupt in CubeMX to allow HAL_UART_Receive_IT functionality
48 * - Use pointer to UART handle when initializing ow with ow_init
49 */
50#include "lwow/lwow.h"
51#include "main.h" /* Generated normally by CubeMX */
52
53#if !__DOXYGEN__
54
55static uint8_t init(void* arg);
56static uint8_t deinit(void* arg);
57static uint8_t set_baudrate(uint32_t baud, void* arg);
58static uint8_t transmit_receive(const uint8_t* tx, uint8_t* rx, size_t len, void* arg);
59
60/* STM32 LL driver for OW */
61const lwow_ll_drv_t
62lwow_ll_drv_stm32_hal = {
63 .init = init,
64 .deinit = deinit,
65 .set_baudrate = set_baudrate,
66 .tx_rx = transmit_receive,
67};
68
69static uint8_t
70init(void* arg) {
71 UART_HandleTypeDef* huart = arg;
72
73 LWOW_ASSERT0("arg != NULL", arg != NULL);
74
75 /* Initialize UART */
76 HAL_UART_DeInit(huart);
77 return HAL_UART_Init(huart) == HAL_OK;
78}
79
80static uint8_t
81deinit(void* arg) {
82 UART_HandleTypeDef* huart = arg;
83
84 LWOW_ASSERT0("arg != NULL", arg != NULL);
85
86 return HAL_UART_DeInit(huart);
87}
88
89static uint8_t
90set_baudrate(uint32_t baud, void* arg) {
91 UART_HandleTypeDef* huart = arg;
92
93 LWOW_ASSERT0("arg != NULL", arg != NULL);
94
95 huart->Init.BaudRate = baud;
96 return init(huart);
97}
98
99static uint8_t
100transmit_receive(const uint8_t* tx, uint8_t* rx, size_t len, void* arg) {
101 UART_HandleTypeDef* huart = arg;
102 uint32_t start;
103
104 LWOW_ASSERT0("arg != NULL", arg != NULL);
105
106 /* Get current HAL tick */
107 start = HAL_GetTick();
108
109 /* Start RX in interrupt mode */
110 HAL_UART_Receive_IT(huart, rx, len);
111
112 /* Process TX in polling mode */
113 HAL_UART_Transmit(huart, (void*)tx, len, 100);
114
115 /* Wait RX to finish */
116 while (huart->RxState != HAL_UART_STATE_READY) {
117 if (HAL_GetTick() - start > 100) {
118 return 0;
119 }
120 }
121
122 return 1;
123}
124
125#endif /* !__DOXYGEN__ */