1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 23:12:45 +01:00
RIOT/cpu/rpx0xx/periph/pio.c

890 lines
29 KiB
C
Raw Normal View History

2021-12-16 14:55:38 +01:00
/*
* Copyright (C) 2021 Otto-von-Guericke Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_rpx0xx
* @ingroup drivers_periph_pio
* @{
*
* @file
* @brief PIO implementation for the RPX0XX
* @details The RPX0XX has 2 PIOs with 4 state machines each
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
*
* @}
*/
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include "periph_conf.h"
#include "periph_cpu.h"
#include "bitarithm.h"
#include "io_reg.h"
#include "pio/pio.h"
2021-12-16 15:05:28 +01:00
#include "periph/pio/i2c.h"
2021-12-16 14:55:38 +01:00
#define ENABLE_DEBUG 0
#include "debug.h"
/* ISR vectors */
static const pio_isr_vec_t *_isr[PIO_NUMOF][PIO_SM_NUMOF];
/* ISR vectors for shared interrupts 0-3 raised by any state machine */
static const pio_isr_sm_vec_t *_isr_sm[PIO_NUMOF][4];
/* locked state machines mask */
static volatile uint32_t _sm_mask[PIO_NUMOF];
/* occupied instruction memory mask */
static volatile uint32_t _instr_mask[PIO_NUMOF];
/* behaviour is only atomic if only one CPU core is used */
static inline bool _atomic_set_mask_u32(volatile uint32_t *dst, uint32_t msk)
{
bool exch = false;
unsigned irq = irq_disable();
if (!(*dst & msk)) {
*dst |= msk;
exch = true;
}
irq_restore(irq);
return exch;
}
/* behaviour is only atomic if only one CPU core is used */
static inline bool _atomic_clear_mask_u32(volatile uint32_t *dst, uint32_t msk)
{
bool exch = false;
unsigned irq = irq_disable();
if (*dst & msk) {
*dst &= ~msk;
exch = true;
}
irq_restore(irq);
return exch;
}
static void _irq(pio_t pio, pio_irq_line_t irq, uint32_t status)
{
(void)irq;
if ((status & PIO0_IRQ0_INTS_SM0_RXNEMPTY_Msk) && _isr[pio][0]
&& _isr[pio][0]->rx_ready) {
_isr[pio][0]->rx_ready(pio, 0);
}
if ((status & PIO0_IRQ0_INTS_SM1_RXNEMPTY_Msk) && _isr[pio][1]
&& _isr[pio][1]->rx_ready) {
_isr[pio][1]->rx_ready(pio, 1);
}
if ((status & PIO0_IRQ0_INTS_SM2_RXNEMPTY_Msk) && _isr[pio][2]
&& _isr[pio][2]->rx_ready) {
_isr[pio][2]->rx_ready(pio, 2);
}
if ((status & PIO0_IRQ0_INTS_SM3_RXNEMPTY_Msk) && _isr[pio][3]
&& _isr[pio][3]->rx_ready) {
_isr[pio][3]->rx_ready(pio, 3);
}
if ((status & PIO0_IRQ0_INTS_SM0_TXNFULL_Msk) && _isr[pio][0]
&& _isr[pio][0]->tx_ready) {
_isr[pio][0]->tx_ready(pio, 0);
}
if ((status & PIO0_IRQ0_INTS_SM1_TXNFULL_Msk) && _isr[pio][1]
&& _isr[pio][1]->tx_ready) {
_isr[pio][1]->tx_ready(pio, 1);
}
if ((status & PIO0_IRQ0_INTS_SM2_TXNFULL_Msk) && _isr[pio][2]
&& _isr[pio][2]->tx_ready) {
_isr[pio][2]->tx_ready(pio, 2);
}
if ((status & PIO0_IRQ0_INTS_SM3_TXNFULL_Msk) && _isr[pio][3]
&& _isr[pio][3]->tx_ready) {
_isr[pio][3]->tx_ready(pio, 3);
}
if ((status & PIO0_IRQ0_INTS_SM0_Msk)) {
assert(pio_irq_get(pio) & PIO_IRQ_MASK(0));
if (_isr_sm[pio][0] && _isr_sm[pio][0]->sm) {
_isr_sm[pio][0]->sm(pio, 0);
}
pio_irq_clear(pio, PIO_IRQ_MASK(0));
}
if ((status & PIO0_IRQ0_INTS_SM1_Msk)) {
assert(pio_irq_get(pio) & PIO_IRQ_MASK(1));
if (_isr_sm[pio][1] && _isr_sm[pio][1]->sm) {
_isr_sm[pio][1]->sm(pio, 1);
}
pio_irq_clear(pio, PIO_IRQ_MASK(1));
}
if ((status & PIO0_IRQ0_INTS_SM2_Msk)) {
assert(pio_irq_get(pio) & PIO_IRQ_MASK(2));
if (_isr_sm[pio][2] && _isr_sm[pio][2]->sm) {
_isr_sm[pio][2]->sm(pio, 2);
}
pio_irq_clear(pio, PIO_IRQ_MASK(2));
}
if ((status & PIO0_IRQ0_INTS_SM3_Msk)) {
assert(pio_irq_get(pio) & PIO_IRQ_MASK(3));
if (_isr_sm[pio][3] && _isr_sm[pio][3]->sm) {
_isr_sm[pio][3]->sm(pio, 3);
}
pio_irq_clear(pio, PIO_IRQ_MASK(3));
}
cortexm_isr_end();
}
void pio_init(pio_t pio)
{
assert(pio <= PIO_NUMOF);
NVIC_EnableIRQ(pio_config[pio].irqn0);
NVIC_EnableIRQ(pio_config[pio].irqn1);
}
void pio_start_programs(void)
{
2021-12-16 15:05:28 +01:00
if (IS_USED(MODULE_PIO_AUTOSTART_I2C)) {
pio_i2c_start_programs();
}
2021-12-16 14:55:38 +01:00
}
pio_sm_t pio_sm_lock(pio_t pio)
{
assert(pio <= PIO_NUMOF);
uint32_t pos = 0;
bool exch;
while ((pos < PIO_SM_NUMOF) && !(exch = _atomic_set_mask_u32(&_sm_mask[pio], 1u << pos))) {
pos++;
}
return exch ? (pio_sm_t)pos : -1;
}
void pio_sm_unlock(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
_atomic_clear_mask_u32(&_sm_mask[pio], (1u << sm));
}
void pio_sm_start(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
io_reg_atomic_set(&dev->CTRL,
((1u << sm) << PIO0_CTRL_CLKDIV_RESTART_Pos) |
((1u << sm) << PIO0_CTRL_SM_ENABLE_Pos));
}
void pio_sm_stop(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
io_reg_atomic_clear(&dev->CTRL, (1u << sm) << PIO0_CTRL_SM_ENABLE_Pos);
}
int pio_alloc_program(pio_t pio, pio_program_t *prog)
{
assert(pio <= PIO_NUMOF);
if (!prog->instr_numof) {
return 0;
}
if (prog->instr_numof > PIO_INSTR_NUMOF) {
return -ENOMEM;
}
/* don´t ((uint32_t)1 << 32) */
uint32_t mask = ((((uint32_t)1 << (prog->instr_numof - 1)) - 1) << 1) | 1;
bool exch = false;
unsigned i = 0;
while ((i <= PIO_INSTR_NUMOF - prog->instr_numof) &&
!(exch = _atomic_set_mask_u32(&_instr_mask[pio], mask << i))) {
i++;
}
if (!exch) {
return -ENOMEM;
}
prog->location = i;
prog->written = false;
return 0;
}
int pio_alloc_program_sm_lock_any(pio_t *pio_ptr, pio_sm_t *sm_ptr, pio_program_t *program)
{
pio_t pio;
pio_sm_t sm = -1;
int alloc = 0;
if (!pio_ptr || !sm_ptr || !program) {
return -EFAULT;
}
for (pio = 0; pio < PIO_NUMOF; pio++) {
if ((alloc = pio_alloc_program(pio, program))) {
continue;
}
if ((sm = pio_sm_lock(pio)) < 0) {
pio_free_program(pio, program);
continue;
}
break;
}
if (sm >= 0) {
*pio_ptr = pio;
*sm_ptr = sm;
return 0;
}
return alloc ? alloc : (int)sm;
}
void pio_free_program(pio_t pio, pio_program_t *prog)
{
assert(pio <= PIO_NUMOF);
if (!prog->instr_numof || prog->instr_numof > PIO_INSTR_NUMOF ||
prog->location < 0 || prog->location >= PIO_INSTR_NUMOF) {
return;
}
/* don´t ((uint32_t)1 << 32) */
uint32_t mask = ((((uint32_t)1 << (prog->instr_numof - 1)) - 1) << 1) | 1;
mask <<= prog->location;
_atomic_clear_mask_u32(&_instr_mask[pio], mask);
prog->location = PIO_PROGRAM_NOT_LOADED;
prog->written = false;
}
int pio_sm_exec(pio_t pio, pio_sm_t sm, pio_instr_t inst) {
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
if (ctrl->execctrl & PIO0_SM0_EXECCTRL_EXEC_STALLED_Msk) {
return -EBUSY;
}
ctrl->instr = inst;
return 0;
}
void pio_sm_exec_block(pio_t pio, pio_sm_t sm, pio_instr_t inst) {
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
while (ctrl->execctrl & PIO0_SM0_EXECCTRL_EXEC_STALLED_Msk) {}
ctrl->instr = inst;
}
int pio_write_program(pio_t pio, pio_program_t *prog, const pio_instr_t *prog_instr)
{
assert(pio <= PIO_NUMOF);
if (prog->location < 0 || prog->location > PIO_INSTR_NUMOF) {
return -EFAULT;
}
PIO0_Type *dev = pio_config[pio].dev;
for (unsigned i = 0; i < prog->instr_numof; i++) {
pio_instr_t inst = prog_instr[i];
/* JMPs are absolute addresses and must be adjusted to the program offset */
if ((inst & PIO_INST_JMP_MASK) == PIO_INST_JMP) {
inst += prog->location;
}
(&dev->INSTR_MEM0 + prog->location)[i] = inst;
}
prog->written = true;
return 0;
}
void pio_sm_reset(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
ctrl->clkdiv = 1u << PIO0_SM0_CLKDIV_INT_Pos;
ctrl->execctrl = 0x1f << PIO0_SM0_EXECCTRL_WRAP_TOP_Pos;
ctrl->shiftctrl = (1u << PIO0_SM0_SHIFTCTRL_OUT_SHIFTDIR_Pos) |
(1u << PIO0_SM0_SHIFTCTRL_IN_SHIFTDIR_Pos);
ctrl->pinctrl = 5u << PIO0_SM0_PINCTRL_SET_COUNT_Pos;
}
void pio_sm_restart(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
io_reg_atomic_set(&dev->CTRL,
((1u << sm) << PIO0_CTRL_SM_RESTART_Pos) |
((1u << sm) << PIO0_CTRL_CLKDIV_RESTART_Pos));
}
void pio_set_isr_vec(pio_t pio, pio_sm_t sm, const pio_isr_vec_t *vec)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
unsigned irq = irq_disable();
/* something is wrong when something overrides an existing isr */
assert(!_isr[pio][sm] || _isr[pio][sm] == vec);
_isr[pio][sm] = vec;
irq_restore(irq);
}
void pio_set_isr_sm_vec(pio_t pio, unsigned irq_num, const pio_isr_sm_vec_t *vec)
{
assert(pio <= PIO_NUMOF);
assert(irq_num < 4); /* irq 0 to 3 are routed to NVIC */
unsigned irq = irq_disable();
/* something is wrong when something overrides an existing isr */
assert(!_isr_sm[pio][irq_num] || _isr_sm[pio][irq_num] == vec);
_isr_sm[pio][irq_num] = vec;
irq_restore(irq);
}
void pio_sm_set_out_pins(pio_t pio, pio_sm_t sm, gpio_t pin_base, unsigned pin_count)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->pinctrl,
(pin_base << PIO0_SM0_PINCTRL_OUT_BASE_Pos) |
(pin_count << PIO0_SM0_PINCTRL_OUT_COUNT_Pos),
PIO0_SM0_PINCTRL_OUT_BASE_Msk | PIO0_SM0_PINCTRL_OUT_COUNT_Msk);
}
void pio_sm_set_in_pins(pio_t pio, pio_sm_t sm, gpio_t pin_base)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->pinctrl,
pin_base << PIO0_SM0_PINCTRL_IN_BASE_Pos,
PIO0_SM0_PINCTRL_IN_BASE_Msk);
}
void pio_sm_set_set_pins(pio_t pio, pio_sm_t sm, gpio_t pin_base, unsigned pin_count)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->pinctrl,
(pin_base << PIO0_SM0_PINCTRL_SET_BASE_Pos) |
(pin_count << PIO0_SM0_PINCTRL_SET_COUNT_Pos),
PIO0_SM0_PINCTRL_SET_BASE_Msk | PIO0_SM0_PINCTRL_SET_COUNT_Msk);
}
void pio_sm_set_sideset_pins(pio_t pio, pio_sm_t sm, gpio_t pin_base)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->pinctrl,
(pin_base << PIO0_SM0_PINCTRL_SIDESET_BASE_Pos),
PIO0_SM0_PINCTRL_SIDESET_BASE_Msk);
}
void pio_sm_set_sideset_count(pio_t pio, pio_sm_t sm, unsigned pin_count, bool enable)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->pinctrl,
((pin_count + !!enable) << PIO0_SM0_PINCTRL_SIDESET_COUNT_Pos),
PIO0_SM0_PINCTRL_SIDESET_COUNT_Msk);
io_reg_write_dont_corrupt(&ctrl->execctrl,
(!!enable) << PIO0_SM0_EXECCTRL_SIDE_EN_Pos,
PIO0_SM0_EXECCTRL_SIDE_EN_Msk);
}
void pio_sm_set_sideset_target(pio_t pio, pio_sm_t sm, bool pindir)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->execctrl,
(!!pindir) << PIO0_SM0_EXECCTRL_SIDE_PINDIR_Pos,
PIO0_SM0_EXECCTRL_SIDE_PINDIR_Msk);
}
pio_sm_clkdiv_t pio_sm_clkdiv(uint32_t f_hz)
{
uint32_t div = CLOCK_CORECLOCK / f_hz;
uint32_t frac = (((uint64_t)100 * CLOCK_CORECLOCK) / f_hz) - (100 * div);
assert(div > 0);
assert((div < PIO_SM_CLKDIV_MAX) || (div == PIO_SM_CLKDIV_MAX && frac == 0));
if (div >= PIO_SM_CLKDIV_MAX) {
div = 0;
frac = 0;
}
return (pio_sm_clkdiv_t){ .div = div, .frac_100 = frac };
}
void pio_sm_set_clkdiv(pio_t pio, pio_sm_t sm, pio_sm_clkdiv_t clk)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
if (clk.div == 0) {
clk.frac_100 = 0;
/* 0 --> 65536 */
}
if (clk.frac_100 >= 100) {
clk.frac_100 /= 10;
}
uint32_t frac = ((((uint16_t)clk.frac_100) * 256) + 50) / 100;
uint32_t val = (clk.div << PIO0_SM0_CLKDIV_INT_Pos) | (frac << PIO0_SM0_CLKDIV_FRAC_Pos);
uint32_t msk = PIO0_SM0_CLKDIV_INT_Msk | PIO0_SM0_CLKDIV_FRAC_Msk;
io_reg_write_dont_corrupt(&ctrl->clkdiv, val, msk);
}
void pio_sm_clkdiv_restart(pio_t pio, unsigned sm_mask)
{
assert(pio <= PIO_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
io_reg_atomic_set(&dev->CTRL, (sm_mask & PIO_SM_ALL) << PIO0_CTRL_CLKDIV_RESTART_Pos);
}
void pio_sm_set_wrap(pio_t pio, pio_sm_t sm, unsigned prog_loc, uint8_t top, uint8_t bottom)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->execctrl,
((prog_loc + bottom) << PIO0_SM0_EXECCTRL_WRAP_BOTTOM_Pos) |
((prog_loc + top) << PIO0_SM0_EXECCTRL_WRAP_TOP_Pos),
PIO0_SM0_EXECCTRL_WRAP_BOTTOM_Msk | PIO0_SM0_EXECCTRL_WRAP_TOP_Msk);
}
void pio_sm_set_jmp_pin(pio_t pio, pio_sm_t sm, gpio_t pin)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->execctrl,
pin << PIO0_SM0_EXECCTRL_JMP_PIN_Pos,
PIO0_SM0_EXECCTRL_JMP_PIN_Msk);
}
void pio_sm_set_in_shift(pio_t pio, pio_sm_t sm, bool right, bool autopush, unsigned threshold)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->shiftctrl,
((!!right) << PIO0_SM0_SHIFTCTRL_IN_SHIFTDIR_Pos) |
((!!autopush) << PIO0_SM0_SHIFTCTRL_AUTOPUSH_Pos) |
((threshold % 32) << PIO0_SM0_SHIFTCTRL_PUSH_THRESH_Pos),
PIO0_SM0_SHIFTCTRL_IN_SHIFTDIR_Msk |
PIO0_SM0_SHIFTCTRL_AUTOPUSH_Msk |
PIO0_SM0_SHIFTCTRL_PUSH_THRESH_Msk);
}
void pio_sm_set_out_shift(pio_t pio, pio_sm_t sm, bool right, bool autopull, unsigned threshold)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->shiftctrl,
((!!right) << PIO0_SM0_SHIFTCTRL_OUT_SHIFTDIR_Pos) |
((!!autopull) << PIO0_SM0_SHIFTCTRL_AUTOPULL_Pos) |
((threshold % 32) << PIO0_SM0_SHIFTCTRL_PULL_THRESH_Pos),
PIO0_SM0_SHIFTCTRL_OUT_SHIFTDIR_Msk |
PIO0_SM0_SHIFTCTRL_AUTOPULL_Msk |
PIO0_SM0_SHIFTCTRL_PULL_THRESH_Msk);
}
void pio_sm_set_fifo_join_rx(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->shiftctrl,
1u << PIO0_SM0_SHIFTCTRL_FJOIN_RX_Pos,
PIO0_SM0_SHIFTCTRL_FJOIN_RX_Msk | PIO0_SM0_SHIFTCTRL_FJOIN_TX_Msk);
}
void pio_sm_set_fifo_join_tx(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_write_dont_corrupt(&ctrl->shiftctrl,
1u << PIO0_SM0_SHIFTCTRL_FJOIN_TX_Pos,
PIO0_SM0_SHIFTCTRL_FJOIN_RX_Msk | PIO0_SM0_SHIFTCTRL_FJOIN_TX_Msk);
}
void pio_sm_reset_fifos(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_atomic_clear(&ctrl->shiftctrl,
(1u << PIO0_SM0_SHIFTCTRL_FJOIN_TX_Pos) |
(1u << PIO0_SM0_SHIFTCTRL_FJOIN_RX_Pos));
}
void pio_sm_clear_fifos(pio_t pio, pio_sm_t sm)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
io_reg_atomic_xor(&ctrl->shiftctrl, (1u << PIO0_SM0_SHIFTCTRL_FJOIN_RX_Pos));
io_reg_atomic_xor(&ctrl->shiftctrl, (1u << PIO0_SM0_SHIFTCTRL_FJOIN_RX_Pos));
}
void pio_irq_enable(pio_t pio, pio_irq_line_t irq, pio_irq_source_t irq_mask)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)irq < PIO_IRQ_LINE_NUMOF);
uint32_t val = irq_mask & PIO_IRQ_ALL;
PIO0_Type *dev = pio_config[pio].dev;
if (irq == PIO_IRQ_LINE_0) {
io_reg_atomic_set(&dev->IRQ0_INTE, val);
}
else if (irq == PIO_IRQ_LINE_1) {
io_reg_atomic_set(&dev->IRQ1_INTE, val);
}
}
void pio_irq_disable(pio_t pio, pio_irq_line_t irq, pio_irq_source_t irq_mask)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)irq < PIO_IRQ_LINE_NUMOF);
uint32_t val = irq_mask & PIO_IRQ_ALL;
PIO0_Type *dev = pio_config[pio].dev;
if (irq == PIO_IRQ_LINE_0) {
io_reg_atomic_clear(&dev->IRQ0_INTE, val);
}
else if (irq == PIO_IRQ_LINE_1) {
io_reg_atomic_clear(&dev->IRQ1_INTE, val);
}
}
int pio_sm_transmit_word(pio_t pio, pio_sm_t sm, uint32_t word)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
if (pio_sm_tx_fifo_full(pio, sm)) {
return -EBUSY;
}
(&dev->TXF0)[sm] = word;
return 0;
}
void pio_sm_transmit_word_block(pio_t pio, pio_sm_t sm, uint32_t word)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
while (pio_sm_tx_fifo_full(pio, sm)) {}
(&dev->TXF0)[sm] = word;
}
void pio_sm_transmit_words_block(pio_t pio, pio_sm_t sm, const uint32_t *words, unsigned count)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
while (count--) {
pio_sm_transmit_word_block(pio, sm, *words++);
}
}
int pio_sm_receive_word(pio_t pio, pio_sm_t sm, uint32_t *word)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
if (pio_sm_rx_fifo_empty(pio, sm)) {
return -ENODATA;
}
uint32_t w = (&dev->RXF0)[sm];
if (word) {
*word = w;
}
return 0;
}
void pio_sm_receive_word_block(pio_t pio, pio_sm_t sm, uint32_t *word)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
while (pio_sm_rx_fifo_empty(pio, sm)) {}
uint32_t w = (&dev->RXF0)[sm];
if (word) {
*word = w;
}
}
void pio_sm_receive_words_block(pio_t pio, pio_sm_t sm, uint32_t *word, unsigned count)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
while (count--) {
pio_sm_receive_word_block(pio, sm, !word ? word : word++);
}
}
uint32_t pio_irq_get(pio_t pio)
{
assert(pio <= PIO_NUMOF);
return pio_config[pio].dev->IRQ;
}
void pio_irq_clear(pio_t pio, unsigned irq_flags)
{
assert(pio <= PIO_NUMOF);
pio_config[pio].dev->IRQ = irq_flags & ((1u << PIO_IRQ_NUMOF) - 1);
}
int pio_sm_init_common(pio_t pio, pio_sm_t sm,
const pio_program_t *prog,
const pio_program_conf_t *conf)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
if (prog->location < 0 ||
prog->location >= PIO_INSTR_NUMOF ||
prog->instr_numof > PIO_INSTR_NUMOF ||
!prog->written ||
conf->pc_start >= prog->instr_numof ||
conf->wrap_top >= prog->instr_numof ||
conf->wrap_bottom >= prog->instr_numof ||
conf->wrap_bottom > conf->wrap_top) {
return -ECANCELED;
}
pio_sm_reset(pio, sm);
pio_sm_clear_debug_txstall(pio, PIO_SM_MASK(sm));
pio_sm_clear_debug_txover(pio, PIO_SM_MASK(sm));
pio_sm_clear_debug_rxunder(pio, PIO_SM_MASK(sm));
pio_sm_clear_debug_rxstall(pio, PIO_SM_MASK(sm));
pio_sm_set_wrap(pio, sm, prog->location, conf->wrap_top, conf->wrap_bottom);
pio_sm_set_sideset_count(pio, sm, conf->sideset_count, conf->sideset_optional);
pio_sm_set_sideset_target(pio, sm, conf->sideset_pindirs);
pio_set_isr_vec(pio, sm, NULL);
/* cannot disable SM interrupts because they are globally used per PIO and
some program might be using it */
pio_irq_disable(pio, PIO_IRQ_LINE_0, (PIO_IRQ_RXNEMPTY_SM0 << sm) |
(PIO_IRQ_TXNFULL_SM0 << sm));
pio_irq_disable(pio, PIO_IRQ_LINE_1, (PIO_IRQ_RXNEMPTY_SM0 << sm) |
(PIO_IRQ_TXNFULL_SM0 << sm));
pio_sm_exec(pio, sm, pio_inst_jmp(PIO_INST_JMP_COND_NONE, (prog->location + conf->pc_start)));
return 0;
}
void pio_sm_set_pindirs_with_mask(pio_t pio, pio_sm_t sm, gpio_t values, gpio_t mask)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
uint32_t pinctrl = ctrl->pinctrl;
while (mask) {
uint8_t pos;
mask = bitarithm_test_and_clear(mask, &pos);
ctrl->pinctrl = (1u << PIO0_SM0_PINCTRL_SET_COUNT_Pos) |
((uint32_t)pos << PIO0_SM0_PINCTRL_SET_BASE_Pos);
pio_sm_exec(pio, sm, pio_inst_set(PIO_INST_SET_DST_PINDIRS, (values >> pos) & 0x1u));
}
ctrl->pinctrl = pinctrl;
}
void pio_sm_set_pins_with_mask(pio_t pio, pio_sm_t sm, gpio_t values, gpio_t mask)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
pio_sm_ctrl_regs_t *ctrl = &PIO_SM_CTRL_BASE(dev)[sm];
uint32_t pinctrl = ctrl->pinctrl;
while (mask) {
uint8_t pos;
mask = bitarithm_test_and_clear(mask, &pos);
ctrl->pinctrl = (1u << PIO0_SM0_PINCTRL_SET_COUNT_Pos) |
((uint32_t)pos << PIO0_SM0_PINCTRL_SET_BASE_Pos);
pio_sm_exec(pio, sm, pio_inst_set(PIO_INST_SET_DST_PINS, (values >> pos) & 0x1u));
}
ctrl->pinctrl = pinctrl;
}
static void _pio_pins_configure(pio_t pio, pio_sm_t sm, const pio_gpio_init_t *pin_init)
{
for (unsigned i = 0; i < pin_init->gpio_count; i++) {
gpio_pad_ctrl_t pad = pin_init->pad;
gpio_io_ctrl_t io = pin_init->io;
io.function_select = pio ? FUNCTION_SELECT_PIO1 : FUNCTION_SELECT_PIO0;
if (pin_init->gpio_direction & (1u << i)) { /* pin is output */
pad.output_disable = 0;
}
else {
pad.input_enable = 1;
}
gpio_set_pad_config(pin_init->gpio_base + i, pad);
gpio_set_io_config(pin_init->gpio_base + i, io);
pio_sm_set_pindirs_with_mask(pio, sm,
pin_init->gpio_direction << (pin_init->gpio_base + i),
0x1u << (pin_init->gpio_base + i));
pio_sm_set_pins_with_mask(pio, sm,
pin_init->gpio_state << (pin_init->gpio_base + i),
0x1u << (pin_init->gpio_base + i));
}
}
void pio_sm_set_set_pins_init(pio_t pio, pio_sm_t sm, const pio_gpio_init_t *pin_init)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
assert(pin_init->gpio_base < 32);
assert(pin_init->gpio_count <= 5);
assert(pin_init->gpio_base + pin_init->gpio_count <= 32);
pio_sm_set_set_pins(pio, sm, pin_init->gpio_base, pin_init->gpio_count);
_pio_pins_configure(pio, sm, pin_init);
}
void pio_sm_set_out_pins_init(pio_t pio, pio_sm_t sm, const pio_gpio_init_t *pin_init)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
assert(pin_init);
assert(pin_init->gpio_base < 32);
assert(pin_init->gpio_count <= 32);
assert(pin_init->gpio_base + pin_init->gpio_count <= 32);
pio_sm_set_out_pins(pio, sm, pin_init->gpio_base, pin_init->gpio_count);
_pio_pins_configure(pio, sm, pin_init);
}
void pio_sm_set_sideset_pins_init(pio_t pio, pio_sm_t sm, const pio_gpio_init_t *pin_init)
{
assert(pio <= PIO_NUMOF);
assert((unsigned)sm < PIO_SM_NUMOF);
assert(pin_init);
assert(pin_init->gpio_base < 32);
assert(pin_init->gpio_count <= 5);
assert(pin_init->gpio_base + pin_init->gpio_count <= 32);
pio_sm_set_sideset_pins(pio, sm, pin_init->gpio_base);
_pio_pins_configure(pio, sm, pin_init);
}
2021-12-16 14:55:38 +01:00
void pio_print_status(pio_t pio)
{
assert(pio <= PIO_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
/* FIFO status */
uint32_t stat = dev->FSTAT;
uint8_t set;
set = (stat & (PIO_SM_ALL << PIO0_FSTAT_TXEMPTY_Pos) >> PIO0_FSTAT_TXEMPTY_Pos);
printf("TXEMPTY: SM0=%d SM1=%d SM2=%d SM3=%d\n",
set & PIO_SM0, set & PIO_SM1, set & PIO_SM2, set & PIO_SM3);
set = (stat & (PIO_SM_ALL << PIO0_FSTAT_TXFULL_Pos) >> PIO0_FSTAT_TXFULL_Pos);
printf("TXFULL: SM0=%d SM1=%d SM2=%d SM3=%d\n",
set & PIO_SM0, set & PIO_SM1, set & PIO_SM2, set & PIO_SM3);
set = (stat & (PIO_SM_ALL << PIO0_FSTAT_RXEMPTY_Pos) >> PIO0_FSTAT_RXEMPTY_Pos);
printf("RXEMPTY: SM0=%d SM1=%d SM2=%d SM3=%d\n",
set & PIO_SM0, set & PIO_SM1, set & PIO_SM2, set & PIO_SM3);
set = (stat & (PIO_SM_ALL << PIO0_FSTAT_RXFULL_Pos) >> PIO0_FSTAT_RXFULL_Pos);
printf("RXFULL: SM0=%d SM1=%d SM2=%d SM3=%d\n",
set & PIO_SM0, set & PIO_SM1, set & PIO_SM2, set & PIO_SM3);
/* program status */
printf("ADDR: SM0=%"PRIu32" SM1=%"PRIu32" SM2=%"PRIu32" SM3=%"PRIu32"\n",
dev->SM0_ADDR, dev->SM1_ADDR, dev->SM2_ADDR, dev->SM3_ADDR);
printf("INSTR: SM0=%"PRIu32" SM1=%"PRIu32" SM2=%"PRIu32" SM3=%"PRIu32"\n",
dev->SM0_INSTR, dev->SM1_INSTR, dev->SM2_INSTR, dev->SM3_INSTR);
}
void pio_print_debug(pio_t pio)
{
assert(pio <= PIO_NUMOF);
PIO0_Type *dev = pio_config[pio].dev;
uint32_t debug = dev->FDEBUG;
uint8_t set;
set = (debug & (PIO_SM_ALL << PIO0_FDEBUG_TXSTALL_Pos) >> PIO0_FDEBUG_TXSTALL_Pos);
printf("TXSTALL: SM0=%d SM1=%d SM2=%d SM3=%d\n",
set & PIO_SM0, set & PIO_SM1, set & PIO_SM2, set & PIO_SM3);
set = (debug & (PIO_SM_ALL << PIO0_FDEBUG_TXOVER_Pos) >> PIO0_FDEBUG_TXOVER_Pos);
printf("TXOVER: SM0=%d SM1=%d SM2=%d SM3=%d\n",
set & PIO_SM0, set & PIO_SM1, set & PIO_SM2, set & PIO_SM3);
set = (debug & (PIO_SM_ALL << PIO0_FDEBUG_RXUNDER_Pos) >> PIO0_FDEBUG_RXUNDER_Pos);
printf("RXUNDER: SM0=%d SM1=%d SM2=%d SM3=%d\n",
set & PIO_SM0, set & PIO_SM1, set & PIO_SM2, set & PIO_SM3);
set = (debug & (PIO_SM_ALL << PIO0_FDEBUG_RXSTALL_Pos) >> PIO0_FDEBUG_RXSTALL_Pos);
printf("RXSTALL: SM0=%d SM1=%d SM2=%d SM3=%d\n",
set & PIO_SM0, set & PIO_SM1, set & PIO_SM2, set & PIO_SM3);
}
void PIO_0_ISR0(void)
{
_irq(0, 0, PIO0->IRQ0_INTS); /* calls cortexm_isr_end() */
}
void PIO_0_ISR1(void)
{
_irq(0, 1, PIO0->IRQ1_INTS); /* calls cortexm_isr_end() */
}
void PIO_1_ISR0(void)
{
_irq(1, 0, PIO1->IRQ0_INTS); /* calls cortexm_isr_end() */
}
void PIO_1_ISR1(void)
{
_irq(1, 1, PIO1->IRQ1_INTS); /* calls cortexm_isr_end() */
}