NMI signal genration bullshit, impl is for tomorrow
This commit is contained in:
parent
c36b0e08b0
commit
a528472828
|
@ -0,0 +1 @@
|
||||||
|
build/
|
|
@ -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)
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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})
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
58
src/main.c
58
src/main.c
|
@ -24,11 +24,41 @@ static void setup_io(void) {
|
||||||
P2SEL0 &= ~(BIT0 | BIT1); // port 2.[01] to eUSCI_A0
|
P2SEL0 &= ~(BIT0 | BIT1); // port 2.[01] to eUSCI_A0
|
||||||
P2SEL1 |= BIT0 | BIT1;
|
P2SEL1 |= BIT0 | BIT1;
|
||||||
|
|
||||||
P1OUT &= ~(BIT0|BIT1|BIT2|BIT3); // P1.[0-3]: status LED and LA trigger debug stuff
|
// BIT4: trigger for pico-controlled NMI
|
||||||
P1DIR |= (BIT0|BIT1|BIT2|BIT3);
|
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
|
PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode
|
||||||
// to activate previously configured port settings
|
// 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) {
|
void NMI_ISR(void) {
|
||||||
SFRIFG1 &= ~NMIIE;
|
SFRIFG1 &= ~NMIIE;
|
||||||
SYSUNIV = 0;
|
SYSUNIV = 0;
|
||||||
++P1OUT;
|
//++P1OUT;
|
||||||
|
P1OUT = ((P1OUT+1) & 15) | (P1OUT & 0xF0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
setup_io();
|
setup_io();
|
||||||
setup_clocks();
|
setup_clocks();
|
||||||
stdio_msp_init();
|
stdio_msp_init();
|
||||||
//SFRIE1 = NMIIE;
|
SFRIE1 = NMIIE;
|
||||||
//SFRRPCR = SYSRSTRE__ENABLE | SYSRSTUP__PULLUP | SYSNMIIES__FALLING | SYSNMI__NMI;
|
SFRRPCR = SYSRSTRE__ENABLE | SYSRSTUP__PULLUP | SYSNMIIES__FALLING | SYSNMI__NMI;
|
||||||
|
// NOTE: RST/#NMI == SBWTDIO
|
||||||
|
|
||||||
memset(regbak, 0, sizeof regbak);
|
memset(regbak, 0, sizeof regbak);
|
||||||
|
|
||||||
|
@ -319,7 +351,19 @@ int main(void) {
|
||||||
puts("hello world!\r\n");
|
puts("hello world!\r\n");
|
||||||
|
|
||||||
done_irq = 0;
|
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();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue