NMI signal genration bullshit, impl is for tomorrow

This commit is contained in:
Triss 2022-04-11 02:00:05 +02:00
parent c36b0e08b0
commit a528472828
7 changed files with 504 additions and 7 deletions

1
nmigen/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

29
nmigen/CMakeLists.txt Normal file
View File

@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.13)
# initialize the SDK based on PICO_SDK_PATH
# note: this must happen before project()
include(pico_sdk_import.cmake)
set(PROJECT nmigen)
project(${PROJECT})
pico_sdk_init()
add_executable(${PROJECT})
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/trigctl.pio)
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/uart_rx.pio)
target_sources(${PROJECT} PRIVATE
main.c
)
target_link_libraries(${PROJECT} PRIVATE pico_stdlib hardware_pwm hardware_pio
hardware_dma pico_multicore cmsis_core
pico_fix_rp2040_usb_device_enumeration)
pico_add_extra_outputs(${PROJECT})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type")
# enable usb output, disable uart output
pico_enable_stdio_usb(${PROJECT} 1)
pico_enable_stdio_uart(${PROJECT} 0)

149
nmigen/main.c Normal file
View File

@ -0,0 +1,149 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <RP2040.h>
#include <system_RP2040.h>
#include <core_cm0plus.h>
#include <hardware/structs/iobank0.h>
#include <hardware/clocks.h>
#include <hardware/dma.h>
#include <hardware/gpio.h>
#include <hardware/irq.h>
#include <hardware/pio.h>
#include <hardware/pwm.h>
#include <pico/stdlib.h>
#include <pico/stdio_usb.h>
#include "trigctl.pio.h"
#include "uart_rx.pio.h"
#define PIN_TRIGGER 14
#define PIN_TRIGGER_POL glitch_positive
#define PIN_NMI 15
#define PIN_NMI_POL glitch_negative
#define PIN_ACK 16
#define PIN_UART 17
#define PIO_UNIT pio0
#define PIOSM_UART 0
#define PIOSM_TRIG 1
#define UART_BAUD 9600
static void init_gpio(void) {
const int func = GPIO_FUNC_PIO0;
// init trigger pin
sio_hw->gpio_oe_clr = 1u << PIN_TRIGGER;
hw_write_masked(&padsbank0_hw->io[PIN_TRIGGER]
, (PADS_BANK0_GPIO0_IE_BITS)
, (PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS)
| (PADS_BANK0_GPIO0_SCHMITT_BITS)
);
hw_write_masked(&iobank0_hw->io[PIN_TRIGGER].ctrl
, (func << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB)
| ((uint)(PIN_TRIGGER_POL ? GPIO_OVERRIDE_INVERT
: GPIO_OVERRIDE_NORMAL) << IO_BANK0_GPIO0_CTRL_INOVER_LSB)
, (IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS)
| (IO_BANK0_GPIO0_CTRL_INOVER_BITS)
);
sio_hw->gpio_clr = 1u << PIN_NMI;
sio_hw->gpio_oe_set = 1u << PIN_NMI;
hw_write_masked(&padsbank0_hw->io[PIN_NMI]
, PADS_BANK0_GPIO0_IE_BITS
| ((uint)GPIO_SLEW_RATE_FAST << PADS_BANK0_GPIO0_SLEWFAST_LSB)
| (PADS_BANK0_GPIO0_DRIVE_VALUE_12MA << PADS_BANK0_GPIO0_DRIVE_LSB)
, PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS
| PADS_BANK0_GPIO0_SLEWFAST_BITS | PADS_BANK0_GPIO0_DRIVE_BITS
);
hw_write_masked(&iobank0_hw->io[PIN_NMI].ctrl
, (func << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB)
| ((uint)(PIN_NMI_POL ? GPIO_OVERRIDE_INVERT
: GPIO_OVERRIDE_NORMAL) << IO_BANK0_GPIO0_CTRL_OUTOVER_LSB)
, IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS | IO_BANK0_GPIO0_CTRL_OUTOVER_BITS
);
sio_hw->gpio_clr = 1u << PIN_ACK;
sio_hw->gpio_oe_set = 1u << PIN_ACK;
gpio_init(PIN_ACK);
gpio_set_dir(PIN_ACK, GPIO_OUT);
gpio_set_function(PIN_ACK, GPIO_FUNC_SIO);
}
static uint off_uart, off_trig;
static void init_pio(void) {
off_uart = pio_add_program(PIO_UNIT, &uart_rx_program);
uart_rx_program_init(PIO_UNIT, PIOSM_UART, off_uart, PIN_UART, UART_BAUD);
off_trig = pio_add_program(PIO_UNIT, &trigctl_program);
trigctl_pio_init(PIO_UNIT, PIOSM_TRIG, off_trig,
trig_source_pin, PIN_NMI, PIN_TRIGGER, PIN_TRIGGER_POL,
PIN_NMI_POL, true, 125); // 1 MHz
const int irq = PIO0_IRQ_1;
irq_set_enabled(irq, false);
trigctl_ack_glitch_irq(PIO_UNIT, PIOSM_TRIG);
trigctl_set_glitch_irq_enabled(PIO_UNIT, PIOSM_TRIG, 1, true);
irq_set_priority(irq, PICO_HIGHEST_IRQ_PRIORITY);
irq_set_enabled(irq, true);
}
static bool uart_poll_ch(uint8_t* ch) {
if (pio_sm_is_rx_fifo_empty(PIO_UNIT, PIOSM_UART)) return false;
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
io_rw_8 *rxfifo_shift = (io_rw_8*)&PIO_UNIT->rxf[PIOSM_UART] + 3;
*ch = *rxfifo_shift;
return true;
}
int main() {
stdio_init_all();
init_gpio();
init_pio();
while (!stdio_usb_connected());
uint32_t delay = 1;
const uint32_t len = 2;
while (true) {
if (pio_sm_is_tx_fifo_empty(PIO_UNIT, PIOSM_TRIG)) {
printf("push offlen\n");
trigctl_push_off_len(PIO_UNIT, PIOSM_TRIG, delay, len);
}
uint8_t ch;
if (uart_poll_ch(&ch)) {
printf("got cmd: %c\n", ch);
switch (ch) {
case '0': delay = 1; break;
case '+': ++delay; break;
case '-': --delay; break;
default: goto noack;
}
printf("send ack\n");
sio_hw->gpio_set = 1u << PIN_ACK;
busy_wait_us_32(50);
sio_hw->gpio_clr = 1u << PIN_ACK;
printf("sent ack\n");
noack:;
}
if (PIO_UNIT->irq & (1u << PIOSM_TRIG)) {
printf("sent nmi\n");
trigctl_ack_glitch_irq(PIO_UNIT, PIOSM_TRIG);
}
}
}

View File

@ -0,0 +1,62 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})

118
nmigen/trigctl.pio Normal file
View File

@ -0,0 +1,118 @@
.program trigctl
; autopull should be on, depth 32
;
; input pin 0: trigger input
;
; set pin 0: glitch output
;
; irq 0 rel: PIO->CM0 "has glitched" signal
; irq 1 rel: CM0->PIO "do a glitch now" signal
public _start:
out x, 32 ; offset
out y, 32 ; length
irq clear 0 rel
public waitinsn:
wait 1 pin 0 ; or "wait irq 1 rel"
offloop:
jmp x-- offloop
set pins, 1
lenloop:
jmp y-- lenloop
set pins, 0
irq set 0 rel
public wait2:
wait 0 pin 0 ; or "nop"
% c-sdk {
enum glitch_polarity {
glitch_positive = 0,
glitch_negative = 1
};
enum trigctl_source {
trig_source_pin,
trig_source_irq
};
static inline void trigctl_pio_init(PIO pio, uint sm, uint prog_offs,
enum trigctl_source trigsrc, uint glitch_pin, uint trig_pin,
enum glitch_polarity trig_in_pol, enum glitch_polarity glitch_out_pol
, bool enable, int divider) {
pio_sm_set_enabled(pio, sm, false);
if (trigsrc == trig_source_irq) {
pio->instr_mem[prog_offs + trigctl_offset_waitinsn] =
pio_encode_wait_irq(true, true, 1);
pio->instr_mem[prog_offs + trigctl_offset_wait2] =
pio_encode_nop();
} else {
pio->instr_mem[prog_offs + trigctl_offset_waitinsn] =
pio_encode_wait_pin(true, 0);
pio->instr_mem[prog_offs + trigctl_offset_wait2] =
pio_encode_wait_pin(false, 0);
}
pio_sm_config c = trigctl_program_get_default_config(prog_offs);
sm_config_set_set_pins(&c, glitch_pin, 1);
sm_config_set_in_pins(&c, trig_pin/*, 1*/);
sm_config_set_out_shift(&c, false, true, 32);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_clkdiv(&c, divider);
if (trigsrc == trig_source_irq) {
sm_config_set_wrap(&c, prog_offs + trigctl_wrap_target,
prog_offs + trigctl_wrap - 1);
}
pio_sm_init(pio, sm, prog_offs, &c);
pio_sm_set_consecutive_pindirs(pio, sm, glitch_pin, 1, true );
pio_sm_set_consecutive_pindirs(pio, sm, trig_pin , 1, false);
pio_sm_set_pins_with_mask(pio, sm, 0, 1u << glitch_pin);
pio_sm_set_enabled(pio, sm, enable);
pio_gpio_init(pio, glitch_pin);
pio_gpio_init(pio, trig_pin);
}
// ony use "use_wfi" when the corresponding IRQ is enabled in the NVIC
static inline void trigctl_wait_glitch_irq(PIO pio, uint sm, bool use_wfi) {
uint mask = 1u << ((sm + 0) & 3);
if (use_wfi) {
while (!(pio->irq & mask)) __WFE();
} else {
while (!(pio->irq & mask)) ;
}
}
static inline void trigctl_ack_glitch_irq(PIO pio, uint sm) {
hw_set_bits(&pio->irq, 1 << ((sm + 0) & 3));
}
// nvic_irqno: corresponding NVIC IRQ will be PIO${pio}_IRQ_${nvic_irqno}
static inline void trigctl_set_glitch_irq_enabled(PIO pio, uint sm, uint nvic_irqno, bool en) {
pio_set_irqn_source_enabled(pio, nvic_irqno, (sm + 0) & 3, en);
}
/*static inline void trigctl_send_trig_irq(PIO pio, uint sm) {
pio->irq_force = 1 << ((sm + 1) & 3);
}*/
static inline void trigctl_push_off_len(PIO pio, uint sm, uint32_t off, uint32_t len) {
while (pio_sm_is_tx_fifo_full(pio, sm)) ;
pio->txf[sm] = off;
while (pio_sm_is_tx_fifo_full(pio, sm)) ;
pio->txf[sm] = len;
}
%}

94
nmigen/uart_rx.pio Normal file
View File

@ -0,0 +1,94 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.program uart_rx_mini
; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
; with the correct timing.
; IN pin 0 is mapped to the GPIO used as UART RX.
; Autopush must be enabled, with a threshold of 8.
wait 0 pin 0 ; Wait for start bit
set x, 7 [10] ; Preload bit counter, delay until eye of first data bit
bitloop: ; Loop 8 times
in pins, 1 ; Sample data
jmp x-- bitloop [6] ; Each iteration is 8 cycles
% c-sdk {
#include "hardware/clocks.h"
#include "hardware/gpio.h"
static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
pio_gpio_init(pio, pin);
gpio_pull_up(pin);
pio_sm_config c = uart_rx_mini_program_get_default_config(offset);
sm_config_set_in_pins(&c, pin); // for WAIT, IN
// Shift to right, autopush enabled
sm_config_set_in_shift(&c, true, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
// SM transmits 1 bit per 8 execution cycles.
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}
.program uart_rx
; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
; break conditions more gracefully.
; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
start:
wait 0 pin 0 ; Stall until start bit is asserted
set x, 7 [10] ; Preload bit counter, then delay until halfway through
bitloop: ; the first data bit (12 cycles incl wait, set).
in pins, 1 ; Shift data bit into ISR
jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles
jmp pin good_stop ; Check stop bit (should be high)
irq 4 rel ; Either a framing error or a break. Set a sticky flag,
wait 1 pin 0 ; and wait for line to return to idle state.
jmp start ; Don't push data if we didn't see good framing.
good_stop: ; No delay before returning to start; a little slack is
push ; important in case the TX clock is slightly too fast.
% c-sdk {
static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
pio_gpio_init(pio, pin);
gpio_pull_up(pin);
pio_sm_config c = uart_rx_program_get_default_config(offset);
sm_config_set_in_pins(&c, pin); // for WAIT, IN
sm_config_set_jmp_pin(&c, pin); // for JMP
// Shift to right, autopush disabled
sm_config_set_in_shift(&c, true, false, 32);
// Deeper FIFO as we're not doing any TX
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
// SM transmits 1 bit per 8 execution cycles.
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
static inline char uart_rx_program_getc(PIO pio, uint sm) {
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3;
while (pio_sm_is_rx_fifo_empty(pio, sm))
tight_loop_contents();
return (char)*rxfifo_shift;
}
%}

View File

@ -24,11 +24,41 @@ static void setup_io(void) {
P2SEL0 &= ~(BIT0 | BIT1); // port 2.[01] to eUSCI_A0
P2SEL1 |= BIT0 | BIT1;
P1OUT &= ~(BIT0|BIT1|BIT2|BIT3); // P1.[0-3]: status LED and LA trigger debug stuff
P1DIR |= (BIT0|BIT1|BIT2|BIT3);
// BIT4: trigger for pico-controlled NMI
P1OUT &= ~(BIT0|BIT1|BIT2|BIT3|BIT4); // P1.[0-3]: status LED and LA trigger debug stuff
P1DIR |= (BIT0|BIT1|BIT2|BIT3|BIT4);
// BIT5: ack from pico
P1OUT &= ~BIT5;
P1DIR &= ~BIT5;
P1SEL0 &= ~BIT5;
P2SEL0 &= ~BIT5;
// uart to pico (eUSCI_A3)
P6OUT = BIT0;
P6REN = BIT0;
P6DIR = 0xff;
P6SEL1 = ~(BIT0|BIT1);
P6SEL0 = BIT0|BIT1 ;
PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode
// to activate previously configured port settings
// uart A3 to pico
UCA3CTLW0 = UCSWRST;
UCA3CTLW0 |= UCSSEL__SMCLK | (0<<9/*UART*/) | (0<<3/*dormant rx*/);
UCA3BRW = 6; // 9600ish baud
UCA3MCTLW |= UCOS16 | UCBRF_1 | 0x2080;
UCA3IE &= ~(UCTXIE|UCRXIE);
UCA3CTLW0 &= ~UCSWRST;
}
static void pico_send_cmd(char cmd) {
while (!(UCA3IFG & UCTXIFG)) ;
UCA3TXBUF = cmd;
}
static void pico_wait_ack(void) {
while (!(P1IN & BIT5)) ;
while ( (P1IN & BIT5)) ;
}
// ---
@ -288,15 +318,17 @@ __attribute__((__interrupt__(UNMI_VECTOR)))
void NMI_ISR(void) {
SFRIFG1 &= ~NMIIE;
SYSUNIV = 0;
++P1OUT;
//++P1OUT;
P1OUT = ((P1OUT+1) & 15) | (P1OUT & 0xF0);
}
int main(void) {
setup_io();
setup_clocks();
stdio_msp_init();
//SFRIE1 = NMIIE;
//SFRRPCR = SYSRSTRE__ENABLE | SYSRSTUP__PULLUP | SYSNMIIES__FALLING | SYSNMI__NMI;
SFRIE1 = NMIIE;
SFRRPCR = SYSRSTRE__ENABLE | SYSRSTUP__PULLUP | SYSNMIIES__FALLING | SYSNMI__NMI;
// NOTE: RST/#NMI == SBWTDIO
memset(regbak, 0, sizeof regbak);
@ -319,7 +351,19 @@ int main(void) {
puts("hello world!\r\n");
done_irq = 0;
do_trace();
__builtin_unreachable();
pico_send_cmd(0);
while (true) {
P1OUT |= BIT4; // send trig
__delay_cycles(10);
P1OUT &= ~BIT4;
pico_send_cmd('+');
pico_wait_ack();
__delay_cycles(10000);
}
/*do_trace();
__builtin_unreachable();*/
}