Skip to content

Commit

Permalink
Add option for GPIO manipulation driver
Browse files Browse the repository at this point in the history
  • Loading branch information
MaJerle committed Aug 21, 2022
1 parent 636396c commit 82b311c
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 4 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ https://www.maximintegrated.com/en/app-notes/index.mvp/id/214
* Written in ANSI C99
* Platform independent, uses custom low-level layer for device drivers
* 1-Wire protocol fits UART specifications at ``9600`` and ``115200`` bauds
* Allows standard one-wire single-gpio manual control (when UARTs are no more available by the system)
* Hardware is responsible for timing characteristics
* Allows DMA on the high-performance microcontrollers
* Different device drivers included
* DS18x20 temperature sensor is natively supported
* DS18B20 temperature sensor is natively supported
* Works with operating system due to hardware timing management
* Separate thread-safe API is available
* API for device scan, reading and writing single bits
Expand Down
3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ Features
* Written in ANSI C99
* Platform independent, uses custom low-level layer for device drivers
* 1-Wire protocol fits UART specifications at ``9600`` and ``115200`` bauds
* Allows standard one-wire single-gpio manual control (when UARTs are no more available by the system)
* Hardware is responsible for timing characteristics

* Allows DMA on the high-performance microcontrollers

* Different device drivers included

* DS18x20 temperature sensor is natively supported
* DS18B20 temperature sensor is natively supported

* Works with operating system due to hardware timing management

Expand Down
12 changes: 10 additions & 2 deletions docs/user-manual/hw-connection.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.. _hw_connection:

Hardware connection with sensor
===============================
Hardware UART connection with sensor
====================================

To be able to successfully use sensors and other devices with embedded systems, these needs to be physically wired with embedded system (or PC).

Expand Down Expand Up @@ -48,5 +48,13 @@ Let's take reset sequence as an example. By specifications, UART has to be confi
.. note::
Please check `official document on Maxim website <https://www.maximintegrated.com/en/design/technical-documents/tutorials/2/214.html>`_ to understand why ``0xF0`` and ``9600`` bauds.

Hardware connection with single pin
===================================

As the protocol name suggests, one-wire is a single wire protocol.
When UART is not available in the system, and when timing constraints may not be a problem, it is possible to use library in classic mode with single GPIO manipulation.

Pin shall be in open-drain mode (when available) and include external pull-up resistor.

.. toctree::
:maxdepth: 2
11 changes: 11 additions & 0 deletions docs/user-manual/porting-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,16 @@ When customer starts a new project using CubeMX, it must:
:linenos:
:caption: Actual implementation of low-level driver for STM32 with HAL drivers

Low-Level driver for manual GPIO control
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

it is possible to use LwOW library even without available UARTs in the device (or if UARTs are being used for something else).
Demo driver, that manipulates GPIO toggling is available in the repository.

.. literalinclude:: ../../lwow/src/system/lwow_ll_stm32_single_gpio_driver.c
:language: c
:linenos:
:caption: LwOW low-level driver for manual GPIO control without UART

.. toctree::
:maxdepth: 2
199 changes: 199 additions & 0 deletions lwow/src/system/lwow_ll_stm32_single_gpio_driver.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* \file lwow_ll_stm32_single_gpio_driver.c
* \brief Driver for non-UART use, with single GPIO
*/

/*
* Copyright (c) 2022 Tilen MAJERLE
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* This file is part of LwOW - Lightweight onewire library.
*
* Author: Tilen MAJERLE <tilen@majerle.eu>
* Version: v3.0.2
*/
#include "stm32l4xx_hal.h"
/* And all other includes */

#if !__DOXYGEN__

/* Pin setting */
#define GPIO_CLK_EN LL_AHB2_GRP1_PERIPH_GPIOB
#define GPIO_PORT GPIOB
#define GPIO_PIN LL_GPIO_PIN_13
#define OW_PIN_LOW LL_GPIO_ResetOutputPin(GPIO_PORT, GPIO_PIN)
#define OW_PIN_HIGH LL_GPIO_SetOutputPin(GPIO_PORT, GPIO_PIN)
#define OW_PIN_INPUT LL_GPIO_SetPinMode(GPIO_PORT, GPIO_PIN, LL_GPIO_MODE_INPUT)
#define OW_PIN_OUTPUT LL_GPIO_SetPinMode(GPIO_PORT, GPIO_PIN, LL_GPIO_MODE_OUTPUT)

/* Macros for irq lock */
#define IRQ_LOCK_DEFINE uint32_t primask = __get_PRIMASK()
#define IRQ_LOCK __disable_irq()
#define IRQ_UNLOCK __set_PRIMASK(primask)

/* Function prototypes for driver */
static uint8_t prv_init(void* arg);
static uint8_t prv_deinit(void* arg);
static uint8_t prv_set_baudrate(uint32_t baud, void* arg);
static uint8_t prv_transmit_receive(const uint8_t* tx, uint8_t* rx, size_t len, void* arg);

/* Global driver structure for application use */
const
lwow_ll_drv_t ow_driver_gpio = {
.init = prv_init,
.deinit = prv_deinit,
.set_baudrate = prv_set_baudrate,
.tx_rx = prv_transmit_receive
};
static uint32_t baudrate; /* Expected baudrate set by the application */

/**
* \brief Actual data exchange function
*
* This is the demo for STM32L4xx; with slight modifications it will work on any other architecture.
*
* Requirements to be provided for application
* - microseconds timing function (example below uses 16-bit timer as source)
* - interrupt locking mechanism
* - GPIO manupulation features (open-drain mode, pull, etc)
*
* \param low_init_pulse_time: Time in microseconds for initial low pulse width
* \param pre_sample_time: Time in us to wait after pin release.
* Bus is samples after time expiration
* \param post_sample_time: Time in us to wait after sample has been completed
* \return Bus value, `1 == high`, `0 == low`
*/
static uint8_t
prv_exch(uint16_t low_init_pulse_time, uint16_t pre_sample_time, uint16_t post_sample_time) {
uint8_t b = 0;
uint16_t time, start_time;
IRQ_LOCK_DEFINE;

/* Lock interrupts and start execution */
IRQ_LOCK;
time = timebase_get_us_tick();

/* Initiate start low pulse */
start_time = time;
OW_PIN_LOW;
OW_PIN_OUTPUT;
while ((uint16_t)((time = timebase_get_us_tick()) - start_time) < low_init_pulse_time) {}

/* Release line and wait for mid pulse */
start_time = time;
OW_PIN_INPUT;
while ((uint16_t)((time = timebase_get_us_tick()) - start_time) < pre_sample_time) {}

/* Read pin state */
b = LL_GPIO_IsInputPinSet(GPIO_PORT, GPIO_PIN);

/* Wait remaining time */
start_time = time;
while ((uint16_t)((time = timebase_get_us_tick()) - start_time) < post_sample_time) {}

IRQ_UNLOCK;

return b;
}

/*******************************************/
/* LwOW driver interface functions */
/*******************************************/
static uint8_t
prv_init(void* arg) {
LL_GPIO_InitTypeDef gpio_init;

/* Peripheral clock enable */
LL_AHB2_GRP1_EnableClock(GPIO_CLK_EN);

/* Configure GPIO pin with open-drain mode */
LL_GPIO_StructInit(&gpio_init);
gpio_init.Mode = LL_GPIO_MODE_INPUT;
gpio_init.Speed = LL_GPIO_SPEED_FREQ_HIGH;
gpio_init.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
gpio_init.Pull = LL_GPIO_PULL_UP;
gpio_init.Pin = GPIO_PIN;
LL_GPIO_Init(GPIO_PORT, &gpio_init);

LWOW_UNUSED(arg);
return 1;
}

static uint8_t
prv_deinit(void* arg) {
LWOW_UNUSED(arg);
return 1;
}

static uint8_t
prv_set_baudrate(uint32_t baud, void* arg) {
LWOW_UNUSED(arg);
baudrate = baud;
return 1;
}

static uint8_t
prv_transmit_receive(const uint8_t* tx, uint8_t* rx, size_t len, void* arg) {
const uint8_t* t = tx;
uint8_t* r = rx;

/*
* For baudrate set at 9600 - by UART definition
* this fits timing only for reset sequence at onewire level
*
* Length must always be zero, or error is returned
*/
if (baudrate == 9600) {
if (len == 1) {
uint8_t v = prv_exch(480, 70, 410);
*r = v ? *t : 0x01;
} else {
return 0;
}
} else if (baudrate == 115200) {
/*
* Regular transmission process
*
* Exchange values and set timings for different events,
* according to the byte value to be transmitted
*/
for (size_t i = 0; i < len; ++i, ++r, ++t) {
uint8_t v = prv_exch(
*t ? 6 : 60,
*t ? 9 : 0,
*t ? 55 : 10
);

/*
* Set value as 0xFF in case of positive reading, 0x00 otherwise.
* This is to be compliant with LwOW UART expectations
*/
*r = v ? 0xFF : 0x00;
}
} else {
return 0;
}
LWOW_UNUSED(arg);
return 1;
}

#endif /* !__DOXYGEN__ */

0 comments on commit 82b311c

Please sign in to comment.