~ruther/avr-shift-registers

ac31ec3d13f7dfc9e2d28fb5249aea17b614d1d0 — František Boháček 5 years ago 1f2a92a
fix: use consts instead of pointers
M simavr/main.c => simavr/main.c +18 -42
@@ 6,62 6,38 @@

int main(void)
{
    DDRB = 0xFF;
    PORTB = 0xFF;

    _delay_ms(100);
    DDRB = 0;
    PORTB = 0;
    // SIPO
    ShiftRegisterHandle sipoSrHandle = avr_sipo_shift_register_create(
        data_position_create(&DDRB, &PORTB, &PINB, 0), // SIPO_SRCLR
        data_position_create(&DDRB, &PORTB, &PINB, 1), // SIPO_SRCLK
        data_position_create(&DDRB, &PORTB, &PINB, 2), // SIPO_SER
        data_position_create(&DDRB, &PORTB, &PINB, 3), // SIPO_OE
        data_position_create(&DDRB, &PORTB, &PINB, 4), // SIPO_RCLK
    const SipoShiftRegister sipoSr = avr_sipo_shift_register_create(
        data_position_create(&PINB, 0), // SIPO_SRCLR
        data_position_create(&PINB, 1), // SIPO_SRCLK
        data_position_create(&PINB, 2), // SIPO_SER
        data_position_create(&PINB, 3), // SIPO_OE
        data_position_create(&PINB, 4), // SIPO_RCLK
        1
    );
    _delay_ms(100);

    avr_sipo_shift_register_init(sipoSrHandle);
    _delay_ms(100);

    avr_sipo_shift_register_write_byte(sipoSrHandle, 207); // 0b11001111
    _delay_ms(100);
    avr_sipo_shift_register_push_data_to_output(sipoSrHandle);
    _delay_ms(100);
    avr_sipo_shift_register_enable_output(sipoSrHandle);
    _delay_ms(100);
    avr_sipo_shift_register_init(sipoSr);

    avr_sipo_shift_register_destroy(sipoSrHandle);
    _delay_ms(100);
    avr_sipo_shift_register_write_byte(sipoSr, 207); // 0b11001111
    avr_sipo_shift_register_push_data_to_output(sipoSr);
    avr_sipo_shift_register_enable_output(sipoSr);

    // ------------
    // PISO
    _delay_ms(100);

    ShiftRegisterHandle pisoSrHandle = avr_piso_shift_register_create(
        data_position_create(&DDRC, &PORTC, &PINC, 0), // PISO_CE
        data_position_create(&DDRC, &PORTC, &PINC, 1), // PISO_CP
        data_position_create(&DDRC, &PORTC, &PINC, 2), // PISO_Q7
        data_position_create(&DDRC, &PORTC, &PINC, 3), // PISO_PL
    const PisoShiftRegister pisoSr = avr_piso_shift_register_create(
        data_position_create(&PINC, 0), // PISO_CE
        data_position_create(&PINC, 1), // PISO_CP
        data_position_create(&PINC, 2), // PISO_Q7
        data_position_create(&PINC, 3), // PISO_PL
        1
    );
    _delay_ms(100);

    avr_piso_shift_register_init(pisoSrHandle);

    avr_piso_shift_register_parallel_load(pisoSrHandle);
    avr_piso_shift_register_read_byte(pisoSrHandle);
    avr_piso_shift_register_init(pisoSr);

    avr_piso_shift_register_destroy(sipoSrHandle);

    DDRB = 0xFF;
    PORTB = 0xFF;

    _delay_ms(100);
    DDRB = 0;
    PORTB = 0;
    avr_piso_shift_register_parallel_load(pisoSr);
    avr_piso_shift_register_read_byte(pisoSr);

    return 0;
}

M src/sr/data_position.c => src/sr/data_position.c +12 -22
@@ 1,42 1,32 @@
#include "shift_register_internal.h"
#include <stdlib.h>

DataPosition* data_position_create(volatile byte* ddr, volatile byte* port, volatile byte* pin, byte position) {
    DataPosition* dp = (DataPosition*) malloc(sizeof(DataPosition));
    dp->ddr = ddr;
    dp->port = port;
    dp->pin = pin;
    dp->position = position;

const DataPosition data_position_create(volatile byte* pin, byte position) {
    DataPosition dp = { pin, position };
    return dp;
}

void data_position_destroy(const DataPosition* position)
{
    free((DataPosition*) position);
}

bool data_position_get_pin(const DataPosition* position)
bool data_position_get_pin(const DataPosition position)
{
    return get_value(position->pin, position->position);
    return get_value(position.pin, position.position);
}

void data_position_set_port(const DataPosition* position)
void data_position_set_port(const DataPosition position)
{
    set_value(position->port, position->position);
    set_value(position.pin + SR_PORT_OFFSET, position.position);
}

void data_position_reset_port(const DataPosition* position)
void data_position_reset_port(const DataPosition position)
{
    reset_value(position->port, position->position);
    reset_value(position.pin + SR_PORT_OFFSET, position.position);
}

void data_position_set_ddr(const DataPosition* position)
void data_position_set_ddr(const DataPosition position)
{
    set_value(position->ddr, position->position);
    set_value(position.pin + SR_DDR_OFFSET, position.position);
}

void data_position_reset_ddr(const DataPosition* position)
void data_position_reset_ddr(const DataPosition position)
{
    reset_value(position->ddr, position->position);
    reset_value(position.pin + SR_DDR_OFFSET, position.position);
}
\ No newline at end of file

M src/sr/piso_shift_register.c => src/sr/piso_shift_register.c +27 -43
@@ 2,72 2,56 @@
#include <util/delay.h>
#include <stdlib.h>

ShiftRegisterHandle avr_piso_shift_register_create(
    const DataPosition* clockEnable,
    const DataPosition* clockPulse,
    const DataPosition* output,
    const DataPosition* parallelLoad,
const PisoShiftRegister avr_piso_shift_register_create(
    const DataPosition clockEnable,
    const DataPosition clockPulse,
    const DataPosition output,
    const DataPosition parallelLoad,
    int waitTime
)
{
    PisoShiftRegister* shiftRegister = (PisoShiftRegister*) calloc(1, sizeof(PisoShiftRegister));

    shiftRegister->output = output;
    shiftRegister->parallelLoad = parallelLoad;
    shiftRegister->shiftRegister.clockEnable = clockEnable;
    shiftRegister->shiftRegister.clockPulse = clockPulse;
    shiftRegister->shiftRegister.waitTime = waitTime;

    return shiftRegister;
    const ShiftRegister shiftRegister = avr_shift_register_create(SR_PISO, clockEnable, clockPulse, waitTime);
    PisoShiftRegister pisoShiftRegister = { shiftRegister, output, parallelLoad };
    return pisoShiftRegister;
}

void avr_piso_shift_register_init(ShiftRegisterHandle shiftRegisterHandle)
{
    PisoShiftRegister* shiftRegister = (PisoShiftRegister*) shiftRegisterHandle;
    
    data_position_reset_ddr(shiftRegister->output);
    data_position_set_ddr(shiftRegister->parallelLoad);
    data_position_set_ddr(shiftRegister->shiftRegister.clockPulse);
    data_position_set_ddr(shiftRegister->shiftRegister.clockEnable);

    data_position_set_port(shiftRegister->parallelLoad);
void avr_piso_shift_register_init(const PisoShiftRegister shiftRegister)
{    
    data_position_reset_ddr(shiftRegister.output);
    data_position_set_ddr(shiftRegister.parallelLoad);
    data_position_set_ddr(shiftRegister.shiftRegister.clockPulse);
    data_position_set_ddr(shiftRegister.shiftRegister.clockEnable);

    avr_shift_register_enable_clock(shiftRegisterHandle);
}
    data_position_set_port(shiftRegister.parallelLoad);

void avr_piso_shift_register_destroy(ShiftRegisterHandle shiftRegisterHandle)
{
    free((PisoShiftRegister*) shiftRegisterHandle);
    avr_shift_register_enable_clock(shiftRegister.shiftRegister);
}

void avr_piso_shift_register_parallel_load(ShiftRegisterHandle shiftRegisterHandle)
void avr_piso_shift_register_parallel_load(const PisoShiftRegister shiftRegister)
{
    PisoShiftRegister* shiftRegister = (PisoShiftRegister*) shiftRegisterHandle;

    data_position_reset_port(shiftRegister->parallelLoad);
    _delay_ms(1);
    data_position_set_port(shiftRegister->parallelLoad);
    data_position_reset_port(shiftRegister.parallelLoad);
    sleep(shiftRegister.shiftRegister.waitTime);
    data_position_set_port(shiftRegister.parallelLoad);
}

void avr_piso_shift_register_shift(ShiftRegisterHandle shiftRegisterHandle)
void avr_piso_shift_register_shift(const PisoShiftRegister shiftRegister)
{
    avr_shift_register_clock_pulse(shiftRegisterHandle);
    avr_shift_register_clock_pulse(shiftRegister.shiftRegister);
}

bool avr_piso_shift_register_read_bit(ShiftRegisterHandle shiftRegisterHandle)
bool avr_piso_shift_register_read_bit(const PisoShiftRegister shiftRegister)
{
    PisoShiftRegister* shiftRegister = (PisoShiftRegister*) shiftRegisterHandle;

    return data_position_get_pin(shiftRegister->output);
    return data_position_get_pin(shiftRegister.output);
}

byte avr_piso_shift_register_read_byte(ShiftRegisterHandle shiftRegisterHandle)
byte avr_piso_shift_register_read_byte(const PisoShiftRegister shiftRegister)
{
    byte output = 0;

    for (int i = 0; i < 8; i++)
    {
        output |= avr_piso_shift_register_read_bit(shiftRegisterHandle) << i;
        output |= avr_piso_shift_register_read_bit(shiftRegister) << i;
        avr_piso_shift_register_shift(shiftRegister);
    }

    return output;

M src/sr/seduce.h => src/sr/seduce.h +114 -103
@@ 1,77 1,80 @@
#ifndef _SHIFT_REGISTERS_SEDUCE
#define _SHIFT_REGISTERS_SEDUCE

// TODO: make this working with flash memory so the data is not placed on RAM
// TODO: assume PINB is x. then DDRB is x + 1 and PORTB is x + 2.
#ifndef SR_DDR_OFFSET
    #define SR_DDR_OFFSET 1
#endif

/**
 * @file seduce.h
 * @author Rutherther
 * @date 9 Sep 2020
 * @brief File containing public exports of the library.
 * 
 * This header should be included in projects that use this library.
 * There aren't any other headers that should be imported.
 * Other headers suffixed using _internal should be used only
 * internally from within the library.
 * 
 * @see DataPosition
 * @see ShiftRegisterHandle
 */
#ifndef SR_PORT_OFFSET
    #define SR_PORT_OFFSET 2
#endif

/**
 * @brief Handle to work with the shift registers.
 * 
 * This handle can be obtained using @see avr_piso_shift_register_init for PISO
 * or @see avr_sipo_shift_register_init for SIPO.
 * PISO stands for parallel-in/serial-out (used for getting input from shift register).
 * SIPO stands for serial-in/parallel-out (used for passing output using shift register).
 * 
 */
typedef void* ShiftRegisterHandle;
typedef unsigned char bool;
typedef unsigned char byte;

/**
 * @brief Hold data port info.
 * 
 * Structure used to hold DDR, PORT and PIN registers
 * Structure used to hold PIN registers
 * along with a bit position.
 * 
 * DDR and PORT registers will be automatically located
 * to save some RAM. offset of DDR can be set
 * using #define SR_DDR_OFFSET (default 1). For PORT use
 * #define SR_PORT_OFFSET (default 2). This number is then
 * added to the PIN address
 * 
 * Can be used to dynamically save a position of I/O .
 * 
 * @note Function @see data_position_create can be used as an shorthand for creating DataPosition.
 * 
 * Example usage:
 * @code
 *  data_position_create(&DDRA, &PORTA, &PINA, 1); // Pass position 1 of PINA
 *  data_position_create(&PINA, 1); // Pass position 1 of PINA
 * @endcode
 */
typedef struct DataPosition {
    volatile byte* ddr;
    volatile byte* port;
    volatile byte* pin;
    byte position;
} DataPosition;

typedef enum {
    SR_PISO,
    SR_SIPO
} ShiftRegisterTypeHeader;

typedef struct {
    const ShiftRegisterTypeHeader type;
    const DataPosition clockEnable;
    const DataPosition clockPulse;
    int waitTime;
} ShiftRegister;

typedef struct {
    const ShiftRegister shiftRegister;
    const DataPosition output;
    const DataPosition parallelLoad;
} PisoShiftRegister;

typedef struct {
    const ShiftRegister shiftRegister;
    const DataPosition input;
    const DataPosition outputEnable;
    const DataPosition pushOutput;
} SipoShiftRegister;

/**
 * @brief Create DataPosition struct.
 * 
 * @param ddr Pointer to DDR register (for example &DDRA).
 * @param port Pointer to PORT register (for example &PORTA).
 * Pointers to PORT and DDR are automatically calculated.
 * Check out DataPosition documentation for more information.
 * 
 * @param pin Pointer to PIN register (for example &PINA).
 * @param position Position within the register. 
 * @return DataPosition 
 * @note 0 is for LSB. 7 is for MSB. PORTA1 can be used.
 */
extern DataPosition* data_position_create(volatile byte* ddr, volatile byte* port, volatile byte* pin, byte position);

/**
 * @brief Destroy DataPosition
 * 
 * @param position 
 */
extern void data_position_destroy(const DataPosition* position);
extern const DataPosition data_position_create(volatile byte* pin, byte position);

/**
 * @brief Get PIN value of DataPosition.


@@ 80,7 83,7 @@ extern void data_position_destroy(const DataPosition* position);
 * @return true When PIN (input) is HIGH.
 * @return false When PIN (input) is LOW.
 */
extern bool data_position_get_pin(const DataPosition* position);
extern bool data_position_get_pin(const DataPosition position);

/**
 * @brief Set PORT value of DataPosition.


@@ 91,7 94,7 @@ extern bool data_position_get_pin(const DataPosition* position);
 * 
 * @param position 
 */
extern void data_position_set_port(const DataPosition* position);
extern void data_position_set_port(const DataPosition position);

/**
 * @brief Reset PORT value of DataPosition.


@@ 102,7 105,7 @@ extern void data_position_set_port(const DataPosition* position);
 * 
 * @param position 
 */
extern void data_position_reset_port(const DataPosition* position);
extern void data_position_reset_port(const DataPosition position);

/**
 * @brief Set DDR value of DataPosition


@@ 111,7 114,7 @@ extern void data_position_reset_port(const DataPosition* position);
 * 
 * @param position 
 */
extern void data_position_set_ddr(const DataPosition* position);
extern void data_position_set_ddr(const DataPosition position);

/**
 * @brief Reset DDR value of DataPosition.


@@ 120,7 123,7 @@ extern void data_position_set_ddr(const DataPosition* position);
 * 
 * @param position 
 */
extern void data_position_reset_ddr(const DataPosition* position);
extern void data_position_reset_ddr(const DataPosition position);

/*******************************************************************************
 *                                                                             *


@@ 130,14 133,36 @@ extern void data_position_reset_ddr(const DataPosition* position);
 *******************************************************************************/

/**
 * @brief Create shift register.
 * 
 * This function creates generic shift register.
 * Functions beginning with avr_piso_shift_register may be used
 * with this type of ShiftRegister.
 * 
 * @param type
 * @param clockEnable
 * @param clockPulse
 * @param waitTime
 * @return ShiftRegister 
 * 
 * @note You should always init the shift register after creating it. Use @see avr_piso_shift_register_init.
 */
extern const ShiftRegister avr_shift_register_create(
    ShiftRegisterTypeHeader type,
    const DataPosition clockEnable,
    const DataPosition clockPulse,
    int waitTime
);

/**
 * @brief Send clock pulse to shift register.
 * 
 * This function makes the clockPulse position HIGH for specified waitTime
 * Then makes it LOW again.`
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister
 */
extern void avr_shift_register_clock_pulse(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_shift_register_clock_pulse(const ShiftRegister shiftRegister);

/**
 * @brief Enable shift register clock.


@@ 149,10 174,10 @@ extern void avr_shift_register_clock_pulse(ShiftRegisterHandle shiftRegisterHand
 * For SIPO registers if clockEnable is made low
 * the register is also cleared.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister
 * @note This function will be called in the init function.
 */
extern void avr_shift_register_enable_clock(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_shift_register_enable_clock(const ShiftRegister shiftRegister);

/**
 * @brief Disable shift register clock.


@@ 162,9 187,9 @@ extern void avr_shift_register_enable_clock(ShiftRegisterHandle shiftRegisterHan
 * 
 * @note some SIPO registers can be cleared using this function.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister
 */
extern void avr_shift_register_disable_clock(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_shift_register_disable_clock(const ShiftRegister shiftRegister);

/*******************************************************************************
 *                                                                             *


@@ 186,15 211,15 @@ extern void avr_shift_register_disable_clock(ShiftRegisterHandle shiftRegisterHa
 * @param output Can be specified as Q7 in datasheet. Be careful not to use negative Q7.
 * @param parallelLoad Can be specified as PL.
 * @param waitTime Used to wait when pulsing the clock
 * @return ShiftRegisterHandle 
 * @return PisoShiftRegister 
 * 
 * @note You should always init the shift register after creating it. Use @see avr_piso_shift_register_init.
 */
extern ShiftRegisterHandle avr_piso_shift_register_create(
    const DataPosition* clockEnable,
    const DataPosition* clockPulse,
    const DataPosition* output,
    const DataPosition* parallelLoad,
extern const PisoShiftRegister avr_piso_shift_register_create(
    const DataPosition clockEnable,
    const DataPosition clockPulse,
    const DataPosition output,
    const DataPosition parallelLoad,
    int waitTime
);



@@ 206,16 231,9 @@ extern ShiftRegisterHandle avr_piso_shift_register_create(
 * 
 * @see avr_shift_register_enable_clock is also called to enable the clock.
 * 
 * @param shiftRegisterHandle
 * @param shiftRegister
 */
extern void avr_piso_shift_register_init(ShiftRegisterHandle shiftRegisterHandle);

/**
 * @brief Destroy and free PISO shift register memory
 * 
 * @param shiftRegisterHandle 
 */
extern void avr_piso_shift_register_destroy(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_piso_shift_register_init(const PisoShiftRegister shiftRegister);

/**
 * @brief Asynchronously load the data


@@ 225,9 243,9 @@ extern void avr_piso_shift_register_destroy(ShiftRegisterHandle shiftRegisterHan
 * PL port will be set LOW and then back
 * HIGH after waitTime has passed.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 */
extern void avr_piso_shift_register_parallel_load(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_piso_shift_register_parallel_load(const PisoShiftRegister shiftRegister);

/**
 * @brief Shift next bit


@@ 235,9 253,9 @@ extern void avr_piso_shift_register_parallel_load(ShiftRegisterHandle shiftRegis
 * This function shifts next bit from the PISO shift register.
 * It just makes the clockPulse HIGH and then LOW.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 */
extern void avr_piso_shift_register_shift(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_piso_shift_register_shift(const PisoShiftRegister shiftRegister);

/**
 * @brief Read current bit


@@ 247,11 265,11 @@ extern void avr_piso_shift_register_shift(ShiftRegisterHandle shiftRegisterHandl
 * 
 * @note You can read the whole byte using @see avr_piso_shift_register_read_byte
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 * @return true 
 * @return false 
 */
extern bool avr_piso_shift_register_read_bit(ShiftRegisterHandle shiftRegisterHandle);
extern bool avr_piso_shift_register_read_bit(const PisoShiftRegister shiftRegister);

/**
 * @brief Read byte from the shift register


@@ 261,10 279,10 @@ extern bool avr_piso_shift_register_read_bit(ShiftRegisterHandle shiftRegisterHa
 * 
 * @note You can read one bit using @see avr_piso_shift_register_read_bit
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 * @return byte 
 */
extern byte avr_piso_shift_register_read_byte(ShiftRegisterHandle shiftRegisterHandle);
extern byte avr_piso_shift_register_read_byte(const PisoShiftRegister shiftRegister);

/*******************************************************************************
 *                                                                             *


@@ 291,12 309,12 @@ extern byte avr_piso_shift_register_read_byte(ShiftRegisterHandle shiftRegisterH
 * 
 * @note You should always init the shift register after creating it. Use @see avr_sipo_shift_register_init.
 */
extern ShiftRegisterHandle avr_sipo_shift_register_create(
    const DataPosition* clockEnable, // SRCLR
    const DataPosition* clockPulse, // SRCLK
    const DataPosition* input, // SER
    const DataPosition* outputEnable, // OE
    const DataPosition* pushOutput, // RCLK
extern const SipoShiftRegister avr_sipo_shift_register_create(
    const DataPosition clockEnable, // SRCLR
    const DataPosition clockPulse, // SRCLK
    const DataPosition input, // SER
    const DataPosition outputEnable, // OE
    const DataPosition pushOutput, // RCLK
    int waitTime
);



@@ 308,16 326,9 @@ extern ShiftRegisterHandle avr_sipo_shift_register_create(
 * 
 * @see avr_shift_register_enable_clock is also called to enable the clock.
 * 
 * @param shiftRegisterHandle
 */
extern void avr_sipo_shift_register_init(ShiftRegisterHandle shiftRegisterHandle);

/**
 * @brief Destroy and free SIPO shift register memory
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister
 */
extern void avr_sipo_shift_register_destroy(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_sipo_shift_register_init(const SipoShiftRegister shiftRegister);

/**
 * @brief Shifts data by one position.


@@ 325,9 336,9 @@ extern void avr_sipo_shift_register_destroy(ShiftRegisterHandle shiftRegisterHan
 * This function shifts next bit from the PISO shift register.
 * It just makes the clockPulse HIGH and then LOW.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 */
extern void avr_sipo_shift_register_shift(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_sipo_shift_register_shift(const SipoShiftRegister shiftRegister);

/**
 * @brief Write one bit to the shift register.


@@ 337,11 348,11 @@ extern void avr_sipo_shift_register_shift(ShiftRegisterHandle shiftRegisterHandl
 * 
 * @note You can read the whole byte using @see avr_sipo_shift_register_write_byte
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 * @param data 
 * @param position 
 */
extern void avr_sipo_shift_register_write_bit(ShiftRegisterHandle shiftRegisterHandle, byte data, int position);
extern void avr_sipo_shift_register_write_bit(const SipoShiftRegister shiftRegister, byte data, int position);

/**
 * @brief Write whole byte to the shift register.


@@ 351,10 362,10 @@ extern void avr_sipo_shift_register_write_bit(ShiftRegisterHandle shiftRegisterH
 * 
 * @note You can write only one bit using @see avr_sipo_shift_register_write_bit
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 * @param data 
 */
extern void avr_sipo_shift_register_write_byte(ShiftRegisterHandle shiftRegisterHandle, byte data);
extern void avr_sipo_shift_register_write_byte(const SipoShiftRegister shiftRegister, byte data);

/**
 * @brief Enable output DataPosition


@@ 362,9 373,9 @@ extern void avr_sipo_shift_register_write_byte(ShiftRegisterHandle shiftRegister
 * This function enables the output so the shift register
 * outputs the data shifted in it.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 */
extern void avr_sipo_shift_register_enable_output(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_sipo_shift_register_enable_output(const SipoShiftRegister shiftRegister);

/**
 * @brief Disable output DataPosition


@@ 372,9 383,9 @@ extern void avr_sipo_shift_register_enable_output(ShiftRegisterHandle shiftRegis
 * This function disables the output so the shift register
 * doesn't output anything.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 */
extern void avr_sipo_shift_register_disable_output(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_sipo_shift_register_disable_output(const SipoShiftRegister shiftRegister);

/**
 * @brief Psuh data to output


@@ 383,9 394,9 @@ extern void avr_sipo_shift_register_disable_output(ShiftRegisterHandle shiftRegi
 * to the storage register. That means the data you shift
 * in will be set only after you call this function.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 */
extern void avr_sipo_shift_register_push_data_to_output(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_sipo_shift_register_push_data_to_output(const SipoShiftRegister shiftRegister);

/**
 * @brief Disable and enable clock to reset the SR value


@@ 394,8 405,8 @@ extern void avr_sipo_shift_register_push_data_to_output(ShiftRegisterHandle shif
 * and enables the clock. Doing that the register will
 * be reset.
 * 
 * @param shiftRegisterHandle 
 * @param shiftRegister 
 */
extern void avr_sipo_shift_register_reset(ShiftRegisterHandle shiftRegisterHandle);
extern void avr_sipo_shift_register_reset(const SipoShiftRegister shiftRegister);

#endif
\ No newline at end of file

M src/sr/shift_register.c => src/sr/shift_register.c +17 -19
@@ 3,32 3,30 @@
#include <util/delay.h>
#include <stdlib.h>

void avr_shift_register_destroy(ShiftRegisterHandle shiftRegisterHandle)
const ShiftRegister avr_shift_register_create(
    ShiftRegisterTypeHeader type,
    const DataPosition clockEnable,
    const DataPosition clockPulse,
    int waitTime
)
{
    free((ShiftRegister*) shiftRegisterHandle);
    ShiftRegister sr = { type, clockEnable, clockPulse, waitTime };
    return sr;
}

void avr_shift_register_clock_pulse(ShiftRegisterHandle shiftRegisterHandle)
{
    ShiftRegister* sr = (ShiftRegister*) shiftRegisterHandle;
    
    data_position_set_port(sr->clockPulse);
    _delay_ms(1);
    data_position_reset_port(sr->clockPulse);
void avr_shift_register_clock_pulse(ShiftRegister shiftRegister)
{    
    data_position_set_port(shiftRegister.clockPulse);
    sleep(shiftRegister.waitTime);
    data_position_reset_port(shiftRegister.clockPulse);
}

void avr_shift_register_enable_clock(ShiftRegisterHandle shiftRegisterHandle)
void avr_shift_register_enable_clock(ShiftRegister shiftRegister)
{
    ShiftRegister* sr = (ShiftRegister*) shiftRegisterHandle;
    data_position_set_port(sr->clockEnable);

    sr->clockEnabled = 1;
    data_position_set_port(shiftRegister.clockEnable);
}

void avr_shift_register_disable_clock(ShiftRegisterHandle shiftRegisterHandle)
void avr_shift_register_disable_clock(ShiftRegister shiftRegister)
{
    ShiftRegister* sr = (ShiftRegister*) shiftRegisterHandle;
    data_position_reset_port(sr->clockEnable);

    sr->clockEnabled = 0;
    data_position_reset_port(shiftRegister.clockEnable);
}
\ No newline at end of file

M src/sr/shift_register_internal.h => src/sr/shift_register_internal.h +1 -29
@@ 8,34 8,6 @@ void set_value(volatile byte* reg, byte position);
void reset_value(volatile byte* reg, byte position);
bool get_value(volatile byte* reg, byte position);

typedef enum {
    SR_PISO,
    SR_SIPO
} ShiftRegisterTypeHeader;

typedef struct {
    ShiftRegisterTypeHeader type;
} ShiftRegisterHeader;

typedef struct {
    ShiftRegisterHeader header;
    const DataPosition* clockEnable;
    const DataPosition* clockPulse;
    int waitTime;
    bool clockEnabled;
} ShiftRegister;

typedef struct {
    ShiftRegister shiftRegister;
    const DataPosition* output;
    const DataPosition* parallelLoad;
} PisoShiftRegister;

typedef struct {
    ShiftRegister shiftRegister;
    const DataPosition* input;
    const DataPosition* outputEnable;
    const DataPosition* pushOutput;
} SipoShiftRegister;
void sleep(byte milliseconds);

#endif
\ No newline at end of file

M src/sr/sipo_shift_register.c => src/sr/sipo_shift_register.c +37 -55
@@ 2,94 2,76 @@
#include <util/delay.h>
#include <stdlib.h>

ShiftRegisterHandle avr_sipo_shift_register_create(
    const DataPosition* clockEnable,
    const DataPosition* clockPulse,
    const DataPosition* input,
    const DataPosition* outputEnable,
    const DataPosition* pushOutput,
const SipoShiftRegister avr_sipo_shift_register_create(
    const DataPosition clockEnable,
    const DataPosition clockPulse,
    const DataPosition input,
    const DataPosition outputEnable,
    const DataPosition pushOutput,
    int waitTime
)
{
    SipoShiftRegister* shiftRegister = (SipoShiftRegister*) malloc(sizeof(SipoShiftRegister));

    shiftRegister->input = input;
    shiftRegister->outputEnable = outputEnable;
    shiftRegister->pushOutput = pushOutput;
    shiftRegister->shiftRegister.clockEnable = clockEnable;
    shiftRegister->shiftRegister.clockPulse = clockPulse;

    return shiftRegister;
    const ShiftRegister shiftRegister = avr_shift_register_create(SR_SIPO, clockEnable, clockPulse, waitTime);
    SipoShiftRegister sipoShiftRegister = { shiftRegister, input, outputEnable, pushOutput };
    return sipoShiftRegister;
}

void avr_sipo_shift_register_init(ShiftRegisterHandle shiftRegisterHandle)
void avr_sipo_shift_register_init(const SipoShiftRegister shiftRegister)
{
    SipoShiftRegister* shiftRegister = (SipoShiftRegister*) shiftRegisterHandle;

    data_position_set_ddr(shiftRegister->input);
    data_position_set_ddr(shiftRegister->outputEnable);
    data_position_set_ddr(shiftRegister->pushOutput);
    data_position_set_ddr(shiftRegister->shiftRegister.clockPulse);
    data_position_set_ddr(shiftRegister->shiftRegister.clockEnable);

    avr_sipo_shift_register_disable_output(shiftRegisterHandle);
    avr_shift_register_enable_clock(shiftRegisterHandle);
    data_position_set_ddr(shiftRegister.input);
    data_position_set_ddr(shiftRegister.outputEnable);
    data_position_set_ddr(shiftRegister.pushOutput);
    data_position_set_ddr(shiftRegister.shiftRegister.clockPulse);
    data_position_set_ddr(shiftRegister.shiftRegister.clockEnable);

    avr_sipo_shift_register_disable_output(shiftRegister);
    avr_shift_register_enable_clock(shiftRegister.shiftRegister);
}

void avr_sipo_shift_register_destroy(ShiftRegisterHandle shiftRegisterHandle)
void avr_sipo_shift_register_shift(const SipoShiftRegister shiftRegister)
{
    free((SipoShiftRegister *) shiftRegisterHandle);
    avr_shift_register_clock_pulse(shiftRegister.shiftRegister);
}

void avr_sipo_shift_register_shift(ShiftRegisterHandle shiftRegisterHandle)
void avr_sipo_shift_register_write_bit(const SipoShiftRegister shiftRegister, byte data, int position)
{
    avr_shift_register_clock_pulse(shiftRegisterHandle);
}

void avr_sipo_shift_register_write_bit(ShiftRegisterHandle shiftRegisterHandle, byte data, int position)
{
    SipoShiftRegister* shiftRegister = (SipoShiftRegister*) shiftRegisterHandle;

    data &= (1 << position);

    if (data > 0) {
        data_position_set_port(shiftRegister->input);
        data_position_set_port(shiftRegister.input);
    } else {
        data_position_reset_port(shiftRegister->input);
        data_position_reset_port(shiftRegister.input);
    }

    avr_sipo_shift_register_shift(shiftRegisterHandle);
    avr_sipo_shift_register_shift(shiftRegister);
}

void avr_sipo_shift_register_write_byte(ShiftRegisterHandle shiftRegisterHandle, byte data)
void avr_sipo_shift_register_write_byte(const SipoShiftRegister shiftRegister, byte data)
{
    for (int i = 0; i < 8; i++)
    {
        avr_sipo_shift_register_write_bit(shiftRegisterHandle, data, i);
        avr_sipo_shift_register_write_bit(shiftRegister, data, i);
    }
}

void avr_sipo_shift_register_enable_output(ShiftRegisterHandle shiftRegisterHandle)
void avr_sipo_shift_register_enable_output(const SipoShiftRegister shiftRegister)
{
    SipoShiftRegister* shiftRegister = (SipoShiftRegister*) shiftRegisterHandle;
    data_position_reset_port(shiftRegister->outputEnable);
    data_position_reset_port(shiftRegister.outputEnable);
}

void avr_sipo_shift_register_disable_output(ShiftRegisterHandle shiftRegisterHandle)
void avr_sipo_shift_register_disable_output(const SipoShiftRegister shiftRegister)
{
    SipoShiftRegister* shiftRegister = (SipoShiftRegister*) shiftRegisterHandle;
    data_position_set_port(shiftRegister->outputEnable);
    data_position_set_port(shiftRegister.outputEnable);
}

void avr_sipo_shift_register_push_data_to_output(ShiftRegisterHandle shiftRegisterHandle)
void avr_sipo_shift_register_push_data_to_output(const SipoShiftRegister shiftRegister)
{
    SipoShiftRegister* shiftRegister = (SipoShiftRegister*) shiftRegisterHandle;
    data_position_set_port(shiftRegister->pushOutput);
    data_position_set_port(shiftRegister.pushOutput);
}

void avr_sipo_shift_register_reset(ShiftRegisterHandle shiftRegisterHandle)
void avr_sipo_shift_register_reset(const SipoShiftRegister shiftRegister)
{
    avr_shift_register_disable_clock(shiftRegisterHandle);
    _delay_ms(1);
    avr_shift_register_enable_clock(shiftRegisterHandle);
}
    avr_shift_register_disable_clock(shiftRegister.shiftRegister);
    sleep(shiftRegister.shiftRegister.waitTime);
    avr_shift_register_enable_clock(shiftRegister.shiftRegister);
}
\ No newline at end of file

M src/sr/util.c => src/sr/util.c +32 -0
@@ 1,4 1,6 @@
#include "shift_register_internal.h"
#include <stdio.h>
#include <util/delay.h>

void set_value_to(volatile byte* reg, byte position, byte value)
{


@@ 22,4 24,34 @@ void reset_value(volatile byte* reg, byte position)
bool get_value(volatile byte* reg, byte position)
{
    return (*reg & (1 << position)) >> position;
}

void sleep(byte milliseconds)
{
    if (milliseconds % 10 == 0) {
        while (milliseconds > 0) {
            _delay_ms(10);
            milliseconds -= 10;
        }
    } else if (milliseconds % 5 == 0) {
        while (milliseconds > 0) {
            _delay_ms(5);
            milliseconds -= 5;
        }
    } else if (milliseconds % 4 == 0) {
        while (milliseconds > 0) {
            _delay_ms(4);
            milliseconds -= 4;
        }
    } else if (milliseconds % 2 == 0) {
        while (milliseconds > 0) {
            _delay_ms(2);
            milliseconds -= 2;
        }
    } else {
        while (milliseconds > 0) {
            _delay_ms(1);
            milliseconds -= 1;
        }
    }
}
\ No newline at end of file