8000 jacdac support for NRF52 and ESP32 by mmoskal · Pull Request #1 · mmoskal/circuitpython · GitHub
[go: up one dir, main page]

Skip to content

jacdac support for NRF52 and ESP32 #1

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

Draft
wants to merge 34 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4105063
add JACDAC to shared-bindings
jamesadevine Aug 6, 2020
7fb1cd6
add JACDAC to common-hal
MannuLambrichts Aug 17, 2020
1820bd5
first working version of the JACDAC protocol
MannuLambrichts Aug 20, 2020
ba8cf68
code cleanup, bugfixes and improvements
MannuLambrichts Aug 24, 2020
5d39350
Working transmit and receive
jamesadevine Oct 2, 2020
a97bb4c
remove lto for fast builds
jamesadevine Oct 2, 2020
1b3884c
fix time out code
jamesadevine Oct 5, 2020
0fd6e21
Merge remote-tracking branch 'upstream/main' into main
jamesadevine Oct 5, 2020
b4ff27d
Merge branch 'main' into buffer-patch
jamesadevine Oct 5, 2020
8544cd2
complete phys imp
jamesadevine Oct 5, 2020
f8be8ed
feature complete
jamesadevine Oct 6, 2020
443c7ad
re-add lto in Makefile
jamesadevine Oct 6, 2020
54184f2
remove jd_test folder
jamesadevine Oct 6, 2020
7cf9076
return consistent data type from JD shared bindings
jamesadevine Oct 6, 2020
c2598b2
fixup reset code and remove uneccessary panic
jamesadevine Oct 6, 2020
c1f409b
Merge pull request #1 from jamesadevine/buffer-patch
jamesadevine Oct 6, 2020
0f40eb9
Merge remote-tracking branch 'james/jacdac' into jacdac2
mmoskal Jun 17, 2021
8435f68
format with tools/codeformat.py
mmoskal Jun 17, 2021
3510372
add some comments
mmoskal Jun 23, 2021
8a9a03d
start on jacdac busio rewrite
mmoskal Jun 23, 2021
ddaa04a
Add packet queues
mmoskal Jun 24, 2021
12b7307
Start on jacdac common-hal
mmoskal Jun 24, 2021
04d0a38
port Jacdac single wire serial impl
mmoskal Jun 25, 2021
41db49c
Fixes
mmoskal Jun 26, 2021
a466d93
Add dmesg
mmoskal Jun 28, 2021
b935fdd
Implement jacdac_reset()
mmoskal Jun 28, 2021
5216e2a
reception fixes
mmoskal Jun 29, 2021
ec45fcc
allow unix build
mmoskal Jul 7, 2021
864908e
Fix some races
mmoskal Jul 7, 2021
f2e14e5
fix timeout value
mmoskal Jul 7, 2021
165b5e5
Don't blow up when VM is stopped
mmoskal Jul 8, 2021
7875ce5
rewrite JACDAC.hash
mmoskal Jul 8, 2021
78e4ac0
add msr jacdac iot board
mmoskal Jul 9, 2021
98a3e38
Add busio.JACDAC.uid()
mmoskal Jul 9, 2021
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
Prev Previous commit
Next Next commit
port Jacdac single wire serial impl
  • Loading branch information
mmoskal committed Jun 25, 2021
commit 04d0a38a6442793983ff641dba9afec7488a0734
7 changes: 6 additions & 1 deletion locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,10 @@ msgstr ""
msgid "All channels in use"
msgstr ""

#: ports/esp32s2/common-hal/busio/JACDAC.c
msgid "All context->uart_hw peripherals are in use"
msgstr ""

#: ports/atmel-samd/common-hal/audioio/AudioOut.c
msgid "All event channels in use"
msgstr ""
Expand Down Expand Up @@ -1249,7 +1253,8 @@ msgstr ""
msgid "Invalid Pin"
msgstr ""

#: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c
#: ports/esp32s2/bindings/espidf/__init__.c
#: ports/esp32s2/common-hal/busio/JACDAC.c ports/esp32s2/esp_error.c
#: py/moduerrno.c shared-bindings/busio/JACDAC.c
#: shared-module/rgbmatrix/RGBMatrix.c
msgid "Invalid argument"
Expand Down
322 changes: 314 additions & 8 deletions ports/esp32s2/common-hal/busio/JACDAC.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@
#include "supervisor/shared/translate.h"

#include "common-hal/busio/JACDAC.h"
#include "common-hal/busio/UART.h"

#include "driver/uart.h"
#include "driver/gpio.h"

#define LOG(...) ((void)0)

#define UART_EMPTY_THRESH_DEFAULT (10)
#define UART_FULL_THRESH_DEFAULT (120)
#define UART_TOUT_THRESH_DEFAULT (10)

#define FIFO_BYTE context->uart_hw->ahb_fifo.rw_byte

static IRAM_ATTR void uart_isr(busio_jacdac_obj_t *context);
static void log_pin_pulse(int pinid, int numpulses) {
}

static void jd_timer(busio_jacdac_obj_t *context) {
busio_jacdac_base_callback_t f = context->timer_cb;
Expand All @@ -44,7 +60,33 @@ static void jd_timer(busio_jacdac_obj_t *context) {
}
}

static void jd_panic(void) {
abort();
}

#define CHK(e) \
if ((e) != ESP_OK) \
jd_panic()


void common_hal_busio_jacdac_construct(busio_jacdac_obj_t *context, const mcu_pin_obj_t *pin) {
if (!(1 <= pin->number && pin->number < 32)) {
// we do not support pins from out1_*, and GPIO0 doesn't sound like a good idea either
mp_raise_ValueError(translate("Invalid argument"));
}

context->uart_num = UART_NUM_MAX;
for (uart_port_t num = 0; num < UART_NUM_MAX; num++) {
if (!uart_is_used(num)) {
context->uart_num = num;
}
}
if (context->uart_num == UART_NUM_MAX) {
mp_raise_ValueError(translate("All context->uart_hw peripherals are in use"));
}

context->uart_hw = UART_LL_GET_HW(context->uart_num);

busio_jacdac_init(&context->base);

esp_timer_create_args_t args;
Expand All @@ -54,14 +96,42 @@ void common_hal_busio_jacdac_construct(busio_jacdac_obj_t *context, const mcu_pi
args.name = "JD timeout";
es 8000 p_timer_create(&args, &context->timer);

// TODO
claim_pin(pin);
context->pinobj = pin;
context->pinnum = pin->number;

uart_mark_used(context->uart_num, true);

const uart_config_t uart_config =
{.baud_rate = 1000000,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE};
CHK(uart_param_config(context->uart_num, &uart_config));
CHK(uart_isr_register(context->uart_num, (void (*)(void *))uart_isr, context, 0, NULL));

uart_intr_config_t uart_intr =
{.intr_enable_mask = 0,
.rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT,
.rx_timeout_thresh = 30, // 30us
.txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT};
CHK(uart_intr_config(context->uart_num, &uart_intr));

gpio_set_pull_mode(context->pinnum, GPIO_PULLUP_ONLY);
gpio_set_direction(context->pinnum, GPIO_MODE_INPUT);

common_hal_busio_jacdac_cancel(context);
}

void common_hal_busio_jacdac_deinit(busio_jacdac_obj_t *context) {
busio_jacdac_deinit(&context->base);
esp_timer_stop(context->timer);
esp_timer_delete(context->timer);
context->timer = NULL;
if (context->timer) {
esp_timer_stop(context->timer);
esp_timer_delete(context->timer);
context->timer = NULL;
}
uart_mark_used(context->uart_num, false);
// TODO
}

Expand All @@ -76,7 +146,243 @@ void common_hal_busio_jacdac_set_timer(busio_jacdac_obj_t *context, uint32_t us,
common_hal_mcu_enable_interrupts();
}

extern int common_hal_busio_jacdac_start_tx(busio_jacdac_obj_t *context, const void *data, uint32_t numbytes);
extern void common_hal_busio_jacdac_start_rx(busio_jacdac_obj_t *context, void *data, uint32_t maxbytes);
extern void common_hal_busio_jacdac_cancel(busio_jacdac_obj_t *context);
extern int common_hal_busio_jacdac_wait_high(busio_jacdac_obj_t *context);
static IRAM_ATTR esp_err_t xgpio_set_level(gpio_num_t gpio_num, uint32_t level) {
if (level) {
GPIO.out_w1ts = (1 << gpio_num);
} else {
GPIO.out_w1tc = (1 << gpio_num);
}
return ESP_OK;
}

static IRAM_ATTR void pin_rx(busio_jacdac_obj_t *context) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[context->pinnum], PIN_FUNC_GPIO);
REG_SET_BIT(GPIO_PIN_MUX_REG[context->pinnum], FUN_PU);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[context->pinnum]);
GPIO.enable_w1tc = (0x1 << context->pinnum);
REG_WRITE(GPIO_FUNC0_OUT_SEL_CFG_REG + (context->pinnum * 4), SIG_GPIO_OUT_IDX);
gpio_matrix_in(context->pinnum, uart_periph_signal[context->uart_num].rx_sig, 0);
}

static IRAM_ATTR void pin_tx(busio_jacdac_obj_t *context) {
gpio_matrix_in(GPIO_FUNC_IN_HIGH, uart_periph_signal[context->uart_num].rx_sig, 0); // context->uart_hw
GPIO.pin[context->pinnum].int_type = GPIO_PIN_INTR_DISABLE;
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[context->pinnum], PIN_FUNC_GPIO);
gpio_set_level(context->pinnum, 1);
gpio_matrix_out(context->pinnum, uart_periph_signal[context->uart_num].tx_sig, 0, 0);
}

int common_hal_busio_jacdac_wait_high(busio_jacdac_obj_t *context) {
// we already started RX at this point
return 0;
}

void common_hal_busio_jacdac_cancel(busio_jacdac_obj_t *context) {
context->uart_hw->int_clr.val = 0xffffffff;
context->uart_hw->int_ena.val = UART_BRK_DET_INT_ENA;
context->seen_low = 0;
context->rx_len = context->tx_len = 0;
context->fifo_buf = NULL;
context->rx_ended = 0;
pin_rx(context);
}

static IRAM_ATTR void fill_fifo(busio_jacdac_obj_t *context) {
if (!context->tx_len) {
return;
}

int space = UART_FIFO_LEN - context->uart_hw->status.txfifo_cnt;
if (context->tx_len < space) {
space = context->tx_len;
}

for (int i = 0; i < space; i++) {
FIFO_BYTE = context->fifo_buf[i];
}

context->fifo_buf += space;
context->tx_len -= space;

if (context->tx_len == 0) {
LOG("txbrk");
context->uart_hw->idle_conf.tx_brk_num = 14; // 14us
context->uart_hw->conf0.txd_brk = 1;
context->uart_hw->int_clr.tx_brk_done = 1;
context->uart_hw->int_ena.tx_brk_done = 1;
}

context->uart_hw->int_clr.txfifo_empty = 1;
context->uart_hw->conf1.txfifo_empty_thrhd = UART_EMPTY_THRESH_DEFAULT;
context->uart_hw->int_ena.txfifo_empty = 1;
}

static IRAM_ATTR void read_fifo(busio_jacdac_obj_t *context, int force) {
uart_dev_t *uart_reg = context->uart_hw;
int rx_fifo_len = uart_reg->status.rxfifo_cnt;

if (!force && context->fifo_buf == NULL && rx_fifo_len < UART_FULL_THRESH_DEFAULT - 1) {
return; // read not started yet and we're not overflowing

}
if (rx_fifo_len) {
LOG("rxfifo %d", rx_fifo_len);
int n = rx_fifo_len;
if (n > context->rx_len) {
n = context->rx_len;
}

context->rx_len -= n;
rx_fifo_len -= n;

while (n-- > 0) {
*context->fifo_buf++ = FIFO_BYTE;
}
while (rx_fifo_len-- > 0) {
(void)FIFO_BYTE;
}
}
}

#define END_RX_FLAGS (UART_RXFIFO_TOUT_INT_ST | UART_BRK_DET_INT_ST | UART_FRM_ERR_INT_ST)

static IRAM_ATTR void start_bg_rx(busio_jacdac_obj_t *context) {
read_fifo(context, 1); // flush any data
context->seen_low = 1;
context->uart_hw->int_ena.val |= END_RX_FLAGS | UART_RXFIFO_FULL_INT_ENA;
if (!context->fifo_buf) {
busio_jacdac_line_falling(context);
}
}

static IRAM_ATTR void uart_isr(busio_jacdac_obj_t *context) {
uart_dev_t *uart_reg = context->uart_hw;

uint32_t uart_intr_status = uart_reg->int_st.val;
uart_reg->int_clr.val = uart_intr_status; // clear all

LOG("ISR %x", uart_intr_status);

read_fifo(context, 0);

3262 if (!context->seen_low && (uart_intr_status & UART_BRK_DET_INT_ST)) {
log_pin_pulse(0, 1);
start_bg_rx(context);
} else if (uart_intr_status & UART_TX_BRK_DONE_INT_ST) {
uart_reg->conf0.txd_brk = 0;
common_hal_busio_jacdac_cancel(context);
busio_jacdac_tx_completed(context);
} else if (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST) {
uart_reg->int_ena.txfifo_empty = 0;
fill_fifo(context);
} else if (uart_intr_status & END_RX_FLAGS) {
log_pin_pulse(0, 3);
LOG("end, rx=%d", context->rx_len);
context->data_left = context->rx_len;
int had_buf = context->fifo_buf != NULL;
common_hal_busio_jacdac_cancel(context);
if (had_buf) {
log_pin_pulse(0, 2);
busio_jacdac_rx_completed(context);
} else {
context->rx_ended = 1;
}
}
}

static IRAM_ATTR NOINLINE_ATTR void probe_and_set(volatile uint32_t *oe, volatile uint32_t *inp,
uint32_t mask) {
*oe = *inp & mask;
}

static void tx_race(busio_jacdac_obj_t *context) {
// don't reconnect the pin in the middle of the low-pulse
int timeout = 50000;
while (timeout-- > 0 && gpio_get_level(context->pinnum) == 0) {
;
}
pin_rx(context);
start_bg_rx(context);
}

IRAM_ATTR static void target_wait_us(uint32_t us) {
int64_t later = esp_timer_get_time() + us;
while (esp_timer_get_time() < later) {
;
}
}

IRAM_ATTR int common_hal_busio_jacdac_start_tx(busio_jacdac_obj_t *context, const void *data, uint32_t numbytes) {
if (context->tx_len) {
jd_panic();
}

if (context->seen_low || context->uart_hw->status.rxfifo_cnt != 0) {
return -1;
}

common_hal_mcu_disable_interrupts();

gpio_matrix_in(GPIO_FUNC_IN_HIGH, uart_periph_signal[context->uart_num].rx_sig, 0); // context->uart_hw
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[context->pinnum], PIN_FUNC_GPIO);
GPIO.out_w1tc = (1 << context->pinnum);


probe_and_set(&GPIO.enable_w1ts, &GPIO.in, 1 << context->pinnum);

if (!(GPIO.enable & (1 << context->pinnum))) {
// the line went down in the meantime
tx_race(context);
common_hal_mcu_enable_interrupts();
return -1;
}

target_wait_us(12); // low pulse is 14us with wait of 12 here
xgpio_set_level(context->pinnum, 1);

target_wait_us(36); // 41us from end of low pulse to start bit with wait of 36 here

pin_tx(context);


context->fifo_buf = (uint8_t *)data;
context->tx_len = numbytes;

context->uart_hw->int_clr.val = 0xffffffff;

fill_fifo(context);

common_hal_mcu_enable_interrupts();

return 0;
}

void uart_flush_rx(busio_jacdac_obj_t *context) {
common_hal_mcu_disable_interrupts();
read_fifo(context, 1);
common_hal_mcu_enable_interrupts();
}

void common_hal_busio_jacdac_start_rx(busio_jacdac_obj_t *context, void *data, uint32_t maxbytes) {
if (context->rx_len || context->tx_len) {
jd_panic();
}

log_pin_pulse(0, 1);

context->fifo_buf = data;
context->rx_len = maxbytes;
LOG("ini rx=%d", maxbytes);

uart_flush_rx(context);

log_pin_pulse(0, 2);

if (context->rx_ended) {
context->rx_ended = 0;
context->rx_len = 0;
context->fifo_buf = NULL;
log_pin_pulse(0, 2);
busio_jacdac_rx_completed(context);
}
}
Loading
0