GEX core repository.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gex-core/units/sipo/_sipo_api.c

111 lines
3.1 KiB

7 years ago
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#include "unit_sipo.h"
#define SIPO_INTERNAL
#include "_sipo_internal.h"
7 years ago
static void send_pulse(bool pol, GPIO_TypeDef *port, uint32_t ll)
{
if (pol) {
LL_GPIO_SetOutputPin(port, ll);
}
else {
LL_GPIO_ResetOutputPin(port, ll);
}
__asm_loop(2);
if (pol) {
LL_GPIO_ResetOutputPin(port, ll);
}
else {
LL_GPIO_SetOutputPin(port, ll);
}
}
#pragma GCC push_options
#pragma GCC optimize ("O2")
7 years ago
error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16_t terminal_data)
7 years ago
{
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
if (buflen % priv->data_width != 0) {
dbg("Buflen %d vs width %d", (int)buflen, (int)priv->data_width);
return E_BAD_COUNT; // must be a multiple of the channel count
}
// buffer contains data for the individual data pins, back to back as AAA BBB CCC (whole bytes)
const uint8_t data_width = priv->data_width;
const uint16_t bytelen = buflen / data_width;
const uint16_t mask = priv->data_pins;
uint8_t offsets[16];
for (int i=0; i<16; i++) offsets[i] = (uint8_t) (bytelen * i);
for (int32_t bn = bytelen - 1; bn >= 0; bn--) {
// send the byte
for (int32_t i = 0; i < 8; i++) {
uint16_t packed = 0;
for (int32_t j = data_width - 1; j >= 0; j--) {
packed |= (buffer[bn + offsets[j]] >> i) & 1;
if (j > 0) packed <<= 1;
}
uint16_t spread = pinmask_spread(packed, mask);
priv->data_port->BSRR = spread | (((~spread) & mask) << 16);
// Shift clock pulse
send_pulse(priv->shift_pol, priv->shift_port, priv->shift_ll);
}
}
7 years ago
// load the final data - this may be used by some other circuitry or
// simply to rest the lines at a defined known level
uint16_t spread = pinmask_spread(terminal_data, mask);
priv->data_port->BSRR = spread | (((~spread) & mask) << 16);
7 years ago
send_pulse(priv->store_pol, priv->store_port, priv->store_ll);
return E_SUCCESS;
}
#pragma GCC pop_options
error_t UU_SIPO_DirectData(Unit *unit, uint16_t data_packed)
{
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
uint16_t spread = pinmask_spread(data_packed, priv->data_pins);
priv->data_port->BSRR = spread | (((~spread) & priv->data_pins) << 16);
return E_SUCCESS;
}
error_t UU_SIPO_DirectClear(Unit *unit)
{
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
send_pulse(priv->clear_pol, priv->clear_port, priv->clear_ll);
return E_SUCCESS;
}
error_t UU_SIPO_DirectShift(Unit *unit)
{
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
send_pulse(priv->shift_pol, priv->shift_port, priv->shift_ll);
return E_SUCCESS;
}
error_t UU_SIPO_DirectStore(Unit *unit)
{
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
send_pulse(priv->store_pol, priv->store_port, priv->store_ll);
return E_SUCCESS;
}