Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: shift register #458

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions components/shift_reg/.eil.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: shift_reg
description: Driver for generic shift register interface.
version: 0.0.1
groups:
- misc
code_owners: JaimeAlbq
depends:
- name: driver
- name: log
- name: esp_idf_lib_helpers
thread_safe: yes
targets:
- esp32
- esp8266
- esp32s2
- esp32c3
license: ISC
copyrights:
- name: JaimeAlbq
year: 2022
11 changes: 11 additions & 0 deletions components/shift_reg/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
if(${IDF_TARGET} STREQUAL esp8266)
set(req esp8266 log esp_idf_lib_helpers)
else()
set(req driver log esp_idf_lib_helpers)
endif()

idf_component_register(
SRCS shift_reg.c
INCLUDE_DIRS .
REQUIRES ${req}
)
13 changes: 13 additions & 0 deletions components/shift_reg/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright (c) 2022 Jaime Albuquerque <[email protected]>

Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
7 changes: 7 additions & 0 deletions components/shift_reg/component.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
COMPONENT_ADD_INCLUDEDIRS = .

ifdef CONFIG_IDF_TARGET_ESP8266
COMPONENT_DEPENDS = esp8266 log esp_idf_lib_helpers
else
COMPONENT_DEPENDS = driver log esp_idf_lib_helpers
endif
200 changes: 200 additions & 0 deletions components/shift_reg/shift_reg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
* Copyright (c) 2022 Jaime Albuquerque <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "shift_reg.h"

static char *tag = "shift_reg";

esp_err_t shift_reg_init(shift_reg_config_t *dev)
{
esp_err_t err = ESP_FAIL;

if (dev == NULL)
{
ESP_LOGE(tag, "%s: must have the configuration of the shift register", __func__);
err = ESP_ERR_INVALID_ARG;
return err;
}

dev->reg_value = (uint8_t *)malloc(dev->num_reg); // Create an array with all registers

if (dev->reg_value == NULL)
{
ESP_LOGE(tag, "%s: no heap memory to allocate reg_value", __func__);
err = ESP_ERR_NO_MEM;
return err;
}

memset(dev->reg_value, 0, dev->num_reg); // Start all registers as 0

gpio_config_t io_conf;

// disable interrupt
io_conf.intr_type = GPIO_INTR_DISABLE;

switch (dev->mode.dir)
{
case SHIFT_DIR_OUTPUT:
// set as output mode
io_conf.mode = GPIO_MODE_OUTPUT;
uint32_t buf32_0 = 0;
uint32_t buf32_1 = 0;
uint64_t result = 0;

if (dev->pin.clk >= 32)
buf32_1 |= 1 << (dev->pin.clk - 32);
else
buf32_0 |= 1 << dev->pin.clk;

if (dev->pin.latch >= 32)
buf32_1 |= 1 << (dev->pin.latch - 32);
else
buf32_0 |= 1 << dev->pin.latch;

if (dev->pin.data >= 32)
buf32_1 |= 1 << (dev->pin.data - 32);
else
buf32_0 |= 1 << dev->pin.data;

result = ((uint64_t)buf32_1 << 32) | ((uint64_t)buf32_0 << 0);

io_conf.pin_bit_mask = result;

break;

default:
ESP_LOGE(tag, "%s: Mode of shift register not found", __func__);
err = ESP_ERR_INVALID_ARG;
break;
}
// disable pull-down mode
io_conf.pull_down_en = 0;
// disable pull-up mode
io_conf.pull_up_en = 0;
// configure GPIO with the given settings
err = gpio_config(&io_conf);

return err;
}

esp_err_t shift_reg_deinit(shift_reg_config_t *dev)
{
if (dev == NULL)
{
ESP_LOGE(tag, "%s: must have a valid argument;", __func__);
return ESP_ERR_INVALID_ARG;
}

free(dev->reg_value);
return ESP_OK;
}

esp_err_t shift_reg_send(shift_reg_config_t *dev, uint8_t *data, uint8_t len)
{
esp_err_t err = ESP_FAIL;

if (dev == NULL || len > dev->num_reg || data == NULL)
{
ESP_LOGE(tag, "%s: must have a valid argument;", __func__);
err = ESP_ERR_INVALID_ARG;
return err;
}

if (dev->mode.bit_mode == SHIFT_BIT_MODE_MSB)
{
for (uint8_t i = 0; i < len; i++)
{
shift_reg_send8bits(dev, data[i]);
dev->reg_value[i] = data[i];
}
}
else
{
for (int8_t i = len - 1; i >= 0; i--)
{
shift_reg_send8bits(dev, data[i]);
dev->reg_value[i] = data[i];
}
}

err = ESP_OK;

return err;
}

esp_err_t shift_reg_send8bits(shift_reg_config_t *dev, uint8_t data)
{
esp_err_t err = ESP_FAIL;

if (dev == NULL)
{
ESP_LOGE(tag, "%s: must have a valid argument;", __func__);
err = ESP_ERR_INVALID_ARG;
return err;
}

if (dev->mode.bit_mode == SHIFT_BIT_MODE_MSB)
{
// MSB Mode
for (int8_t i = 7; i >= 0; i--)
{
gpio_set_level(dev->pin.data, (data >> i) & 1);

gpio_set_level(dev->pin.clk, true);
UncleRus marked this conversation as resolved.
Show resolved Hide resolved
ets_delay_us(1);
gpio_set_level(dev->pin.clk, false);
ets_delay_us(1);
}
}
else
{
// LSB Mode
for (int8_t i = 0; i < 8; i++)
{
gpio_set_level(dev->pin.data, (data >> i) & 1);

gpio_set_level(dev->pin.clk, true);
ets_delay_us(1);
gpio_set_level(dev->pin.clk, false);
ets_delay_us(1);
}
}

err = ESP_OK;

return err;
}

esp_err_t shift_reg_latch(shift_reg_config_t *dev)
{
esp_err_t err = ESP_FAIL;

if (dev == NULL)
{
ESP_LOGE(tag, "%s: must have a valid argument;", __func__);
err = ESP_ERR_INVALID_ARG;
return err;
}

gpio_set_level(dev->pin.latch, true);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we need to check if dev is NULL

ets_delay_us(1);
gpio_set_level(dev->pin.latch, false);
ets_delay_us(1);

err = ESP_OK;

return err;
}
143 changes: 143 additions & 0 deletions components/shift_reg/shift_reg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Copyright (c) 2022 Jaime Albuquerque <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
* @file shift_reg.h
* @defgroup shift_reg shift_reg
* @{
*
* ESP-IDF driver for generic shift register using 3 pins:
* - data
* - clock
* - latch
*
*/

#if !defined(__SHIFT_REG__H__)
#define __SHIFT_REG__H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <esp_err.h>
#include <esp_log.h>
#include <driver/gpio.h>
#include <ets_sys.h>

/**
* @brief Direction of the data
*
* @todo Add Input mode
*
*/
typedef enum {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All structs and enums must be commented in doxy-style, like this:

/**
 * This structure is intended to store the device handle and its state.
 */
typedef struct {
    int foo;  //< Special field
} some_device_t;

...

/**
 * Device operational modes
 */
typedef enum {
    MODE_FOO = 0; //< Mode Foo
    MODE_BAR;     //< Mode Bar
} some_mode_t;

SHIFT_DIR_OUTPUT = 0,
} shift_reg_dir_t;

/**
* @brief Register orientation mode
*
*/
typedef enum {
SHIFT_BIT_MODE_LSB = 0,
SHIFT_BIT_MODE_MSB,
} shift_reg_bit_mode_t;

/**
* @brief This structure stores the mode of the shift register
*
*/
typedef struct {
shift_reg_dir_t dir : 2; // Direction mode of the shift register
shift_reg_bit_mode_t bit_mode : 1; // Bit mode
} shift_reg_mode_t;

/**
* @brief This structure stores all used pins to interface with the shift register
*
*/
typedef struct {
gpio_num_t clk; // Clock pin
gpio_num_t data; // Data/Signal pin
gpio_num_t latch; // Latch pin
} shift_reg_pin_t;

/**
* @brief This structure stores all needed configuration of the shift register component
*
*/
typedef struct { // Configuration of shift register
uint8_t num_reg; // Number of shift registers
uint8_t *reg_value; // Last value of all registers
shift_reg_mode_t mode; // Direction adn bit mode
shift_reg_pin_t pin; // Set of pins
} shift_reg_config_t;

/**
* @brief Initialize the microcontroller to do the output
*
* @param dev shift register configuration
* @return `ESP_OK` on success
*/
esp_err_t shift_reg_init(shift_reg_config_t *dev);

/**
* @brief Free used memory
*
* @param dev shift register configuration
* @return `ESP_OK` on success
*/
esp_err_t shift_reg_deinit(shift_reg_config_t *dev);

/**
* @brief Send the whole data
*
* @param dev shift register configuration
* @param data data vector
* @param len length of the data
* @return `ESP_OK` on success
*/
esp_err_t shift_reg_send(shift_reg_config_t *dev, uint8_t *data, uint8_t len);

/**
* @brief Send 1 byte of data
*
* @param dev shift register configuration
* @param data 1 byte data
* @return `ESP_OK` on success
*/
esp_err_t shift_reg_send8bits(shift_reg_config_t *dev, uint8_t data);

/**
* @brief Latch the data inside of the shift register
*
* @param dev shift register configuration
* @return `ESP_OK` on success
*/
esp_err_t shift_reg_latch(shift_reg_config_t *dev);

#ifdef __cplusplus
}
#endif

/**@}*/

#endif // __SHIFT_REG__H__
Loading
Loading