#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.
/**
* @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
*/
/**
* @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
* along with a bit position.
*
* 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
* @endcode
*/
typedef struct {
volatile byte* ddr;
volatile byte* port;
volatile byte* pin;
byte position;
} DataPosition;
/**
* @brief Create DataPosition struct.
*
* @param ddr Pointer to DDR register (for example &DDRA).
* @param port Pointer to PORT register (for example &PORTA).
* @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 const 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);
/**
* @brief Get PIN value of DataPosition.
*
* @param position
* @return true When PIN (input) is HIGH.
* @return false When PIN (input) is LOW.
*/
extern bool data_position_get_pin(const DataPosition* position);
/**
* @brief Set PORT value of DataPosition.
*
* This function makes DataPosition PORT register value 1.
* If the port is OUTPUT, it will output 5V.
* If the port is INPUT, the pull up resistor will be activated.
*
* @param position
*/
extern void data_position_set_port(const DataPosition* position);
/**
* @brief Reset PORT value of DataPosition.
*
* This function makes DataPosition PORT register value 0.
* If the port is OUTPUT, it will output 0V.
* If the port is INPUT, the pull up resistor will be deactivated.
*
* @param position
*/
extern void data_position_reset_port(const DataPosition* position);
/**
* @brief Set DDR value of DataPosition
*
* This function makes DataPosition DDR register value 1 and thus making it OUTPUT.
*
* @param position
*/
extern void data_position_set_ddr(const DataPosition* position);
/**
* @brief Reset DDR value of DataPosition.
*
* This function makes DataPosition DDR register value 0 and thus making it INPUT.
*
* @param position
*/
extern void data_position_reset_ddr(const DataPosition* position);
/*******************************************************************************
* *
* SHIFT REGISTER *
* Part to define basic shift register functions used for both PISO and SIPO *
* *
*******************************************************************************/
/**
* @brief Send clock pulse to shift register.
*
* This function makes the clockPulse position HIGH for specified waitTime
* Then makes it LOW again.`
*
* @param shiftRegisterHandle
*/
extern void avr_shift_register_clock_pulse(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Enable shift register clock.
*
* This function enables the DataPosition for clockEnable.
* The clock must be enabled before using the sift register
* Otherwise the shift register won't do anything.
*
* For SIPO registers if clockEnable is made low
* the register is also cleared.
*
* @param shiftRegisterHandle
* @note This function will be called in the init function.
*/
extern void avr_shift_register_enable_clock(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Disable shift register clock.
*
* This funciton disables the DataPosition for clockEnable.
* @see avr_shift_register_enable_clock for more info
*
* @note some SIPO registers can be cleared using this function.
*
* @param shiftRegisterHandle
*/
extern void avr_shift_register_disable_clock(ShiftRegisterHandle shiftRegisterHandle);
/*******************************************************************************
* *
* PISO *
* Part to define PISO shift register functions to allow shifting and getting *
* input from the parallel-in/serial-out shift register *
* *
*******************************************************************************/
/**
* @brief Create PISO shift register.
*
* This function creates PISO shift register.
* Functions beginning with avr_piso_shift_register may be used
* with this type of ShiftRegister.
*
* @param clockEnable Can be specified as CE in datasheet.
* @param clockPulse Can be specified as CP in datasheet.
* @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
*
* @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,
int waitTime
);
/**
* @brief Setup base values for PISO shift register.
*
* This function initializes the DataPositions so they are correctly set as
* inputs or outputs.
*
* @see avr_shift_register_enable_clock is also called to enable the clock.
*
* @param shiftRegisterHandle
*/
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);
/**
* @brief Asynchronously load the data
*
* This function is used on shift registers
* that have the parallel load port.
* PL port will be set LOW and then back
* HIGH after waitTime has passed.
*
* @param shiftRegisterHandle
*/
extern void avr_piso_shift_register_parallel_load(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Shift next bit
*
* This function shifts next bit from the PISO shift register.
* It just makes the clockPulse HIGH and then LOW.
*
* @param shiftRegisterHandle
*/
extern void avr_piso_shift_register_shift(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Read current bit
*
* This function gets the data from the output.
* It will return 0 for LOW or 1 for HIGH
*
* @note You can read the whole byte using @see avr_piso_shift_register_read_byte
*
* @param shiftRegisterHandle
* @return true
* @return false
*/
extern bool avr_piso_shift_register_read_bit(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Read byte from the shift register
*
* This function gets byte from the output.
* The first value read goes to the LSB.
*
* @note You can read one bit using @see avr_piso_shift_register_read_bit
*
* @param shiftRegisterHandle
* @return byte
*/
extern byte avr_piso_shift_register_read_byte(ShiftRegisterHandle shiftRegisterHandle);
/*******************************************************************************
* *
* SIPO *
* Part to define SIPO shift register functions to allow shifting and passing *
* output to the seiarl-in/parallel-out shift register *
* *
*******************************************************************************/
/**
* @brief Create SIPO shift register handle.
*
* This function creates SIPO shift register.
* Functions beginning with avr_sipo_shift_register may be used
* with this type of ShiftRegister.
*
* @param clockEnable Can be specified as SRCLR in datasheet.
* @param clockPulse Can be specified as SRCLK in datasheet.
* @param input Can be specified as SER in datasheet.
* @param outputEnable Can be specified as OE in datasheet.
* @param pushOutput Can be specified as RCLK in datasheet.
* @param waitTime Used to wait when pulsing the clock
* @return ShiftRegisterHandle
*
* @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
int waitTime
);
/**
* @brief Setup base values for PISO shift register.
*
* This function initializes the DataPositions so they are correctly set as
* inputs or outputs.
*
* @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
*/
extern void avr_sipo_shift_register_destroy(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Shifts data by one position.
*
* This function shifts next bit from the PISO shift register.
* It just makes the clockPulse HIGH and then LOW.
*
* @param shiftRegisterHandle
*/
extern void avr_sipo_shift_register_shift(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Write one bit to the shift register.
*
* This function writes one bit to the shift register.
* Shift function is also called to save the data.
*
* @note You can read the whole byte using @see avr_sipo_shift_register_write_byte
*
* @param shiftRegisterHandle
* @param data
* @param position
*/
extern void avr_sipo_shift_register_write_bit(ShiftRegisterHandle shiftRegisterHandle, byte data, int position);
/**
* @brief Write whole byte to the shift register.
*
* This function writes whole byte to the shift register.
* The first written bit will be the LSB.
*
* @note You can write only one bit using @see avr_sipo_shift_register_write_bit
*
* @param shiftRegisterHandle
* @param data
*/
extern void avr_sipo_shift_register_write_byte(ShiftRegisterHandle shiftRegisterHandle, byte data);
/**
* @brief Enable output DataPosition
*
* This function enables the output so the shift register
* outputs the data shifted in it.
*
* @param shiftRegisterHandle
*/
extern void avr_sipo_shift_register_enable_output(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Disable output DataPosition
*
* This function disables the output so the shift register
* doesn't output anything.
*
* @param shiftRegisterHandle
*/
extern void avr_sipo_shift_register_disable_output(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Psuh data to output
*
* This function pushes the data from the shift register
* to the storage register. That means the data you shift
* in will be set only after you call this function.
*
* @param shiftRegisterHandle
*/
extern void avr_sipo_shift_register_push_data_to_output(ShiftRegisterHandle shiftRegisterHandle);
/**
* @brief Disable and enable clock to reset the SR value
*
* This funciton disables the clock, then waits a bit
* and enables the clock. Doing that the register will
* be reset.
*
* @param shiftRegisterHandle
*/
extern void avr_sipo_shift_register_reset(ShiftRegisterHandle shiftRegisterHandle);
#endif