Add pio-based flux capturing for rp2040
This commit is contained in:
parent
1be36bd7cb
commit
9efb034cba
7 changed files with 221 additions and 11 deletions
|
|
@ -508,6 +508,7 @@ msgstr ""
|
|||
msgid "All event channels in use"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/floppyio/__init__.c
|
||||
#: ports/raspberrypi/common-hal/picodvi/Framebuffer.c
|
||||
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
|
||||
#: ports/raspberrypi/common-hal/usb_host/Port.c
|
||||
|
|
@ -4029,6 +4030,15 @@ msgstr ""
|
|||
msgid "timeout must be < 655.35 secs"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/floppyio/__init__.c
|
||||
msgid "timeout waiting for flux"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/floppyio/__init__.c
|
||||
#: shared-module/floppyio/__init__.c
|
||||
msgid "timeout waiting for index pulse"
|
||||
msgstr ""
|
||||
|
||||
#: shared-module/sdcardio/SDCard.c
|
||||
msgid "timeout waiting for v1 card"
|
||||
msgstr ""
|
||||
|
|
|
|||
|
|
@ -7,3 +7,6 @@ CHIP_VARIANT = RP2040
|
|||
CHIP_FAMILY = rp2
|
||||
|
||||
EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ,W25Q128JV"
|
||||
|
||||
CIRCUITPY_USB_HOST = 0
|
||||
CIRCUITPY_PICODVI = 0
|
||||
|
|
|
|||
195
ports/raspberrypi/common-hal/floppyio/__init__.c
Normal file
195
ports/raspberrypi/common-hal/floppyio/__init__.c
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "bindings/rp2pio/StateMachine.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/digitalio/DigitalInOut.h"
|
||||
#include "shared-bindings/floppyio/__init__.h"
|
||||
#include "common-hal/floppyio/__init__.h"
|
||||
#include "shared-bindings/time/__init__.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
|
||||
static const uint16_t fluxread_program[] = {
|
||||
// ; Count flux pulses and watch for index pin
|
||||
// ; flux input is the 'jmp pin'. index is "pin zero".
|
||||
// ; Counts are in units 3 / F_pio, so e.g., at 30MHz 1 count = 0.1us
|
||||
// ; Count down while waiting for the counter to go HIGH
|
||||
// ; The only counting is down, so C code will just have to negate the
|
||||
// count!
|
||||
// ; Each 'wait one' loop takes 3 instruction-times
|
||||
// wait_one:
|
||||
0x0041, // jmp x--, wait_one_next ; acts as a non-conditional decrement
|
||||
// of x
|
||||
// wait_one_next:
|
||||
0x00c3, // jmp pin wait_zero
|
||||
0x0000, // jmp wait_one
|
||||
// ; Each 'wait zero' loop takes 3 instruction-times, needing one
|
||||
// instruction delay
|
||||
// ; (it has to match the 'wait one' timing exactly)
|
||||
// wait_zero:
|
||||
0x0044, // jmp x--, wait_zero_next ; acts as a non-conditional decrement
|
||||
// of x
|
||||
// wait_zero_next:
|
||||
0x01c3, // jmp pin wait_zero [1]
|
||||
// ; Top bit is index status, bottom 15 bits are inverse of counts
|
||||
// ; Combined FIFO gives 16 entries (8 32-bit entries) so with the
|
||||
// ; smallest plausible pulse of 2us there are 250 CPU cycles available
|
||||
// @125MHz
|
||||
0x4001, // in pins, 1
|
||||
0x402f, // in x, 15
|
||||
// ; Three cycles for the end of loop, so we need to decrement x to make
|
||||
// everything
|
||||
// ; come out right. This has constant timing whether we actually jump back
|
||||
// vs wrapping.
|
||||
0x0040, // jmp x--, wait_one
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PIO pio;
|
||||
uint8_t sm;
|
||||
bool word_available;
|
||||
uint16_t half;
|
||||
} floppy_reader;
|
||||
|
||||
static bool data_available(floppy_reader *reader) {
|
||||
return reader->word_available || !pio_sm_is_rx_fifo_empty(reader->pio, reader->sm);
|
||||
}
|
||||
|
||||
static uint16_t read_fifo(floppy_reader *reader) {
|
||||
if (reader->word_available) {
|
||||
reader->word_available = false;
|
||||
return reader->half;
|
||||
}
|
||||
uint32_t value = pio_sm_get_blocking(reader->pio, reader->sm);
|
||||
reader->half = value >> 16;
|
||||
reader->word_available = true;
|
||||
return value & 0xffff;
|
||||
}
|
||||
|
||||
|
||||
int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index, mp_int_t index_wait_ms) {
|
||||
#define READ_INDEX() (!!(*index_port & index_mask))
|
||||
uint32_t index_mask;
|
||||
volatile uint32_t *index_port = common_hal_digitalio_digitalinout_get_reg(index, DIGITALINOUT_REG_READ, &index_mask);
|
||||
|
||||
memset(buf, 0, len);
|
||||
|
||||
uint32_t pins_we_use = 1 << data->pin->number;
|
||||
|
||||
rp2pio_statemachine_obj_t state_machine;
|
||||
bool ok = rp2pio_statemachine_construct(&state_machine,
|
||||
fluxread_program, MP_ARRAY_SIZE(fluxread_program),
|
||||
FLOPPYIO_SAMPLERATE * 3, // 3 PIO cycles per sample count
|
||||
NULL, 0, // init program
|
||||
NULL, 0, // out
|
||||
index->pin, 1, // in
|
||||
1, 0, // in pull up/down
|
||||
NULL, 0, // set
|
||||
NULL, 0, // sideset
|
||||
0, 0, // initial pin state
|
||||
data->pin, // jump pin
|
||||
pins_we_use, false, true,
|
||||
true, 32, false, // TX setting we don't use
|
||||
true, // Wait for txstall. If we don't, then we'll deinit too quickly.
|
||||
true, 32, true, // move 32 bits at a time
|
||||
false, // claim pins
|
||||
false, // Not user-interruptible.
|
||||
false, // No sideset enable
|
||||
0, -1, // wrap
|
||||
PIO_ANY_OFFSET // offset
|
||||
);
|
||||
if (!ok) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use"));
|
||||
}
|
||||
|
||||
floppy_reader reader = { .pio = state_machine.pio, .sm = state_machine.state_machine, };
|
||||
|
||||
uint8_t *ptr = buf, *end = ptr + len;
|
||||
|
||||
uint64_t index_deadline_us = time_us_64() + index_wait_ms * 1000;
|
||||
|
||||
common_hal_mcu_disable_interrupts();
|
||||
|
||||
// check if flux is arriving
|
||||
uint64_t flux_deadline_us = time_us_64() + 20;
|
||||
while (pio_sm_is_rx_fifo_empty(reader.pio, reader.sm)) {
|
||||
if (time_us_64() > flux_deadline_us) {
|
||||
common_hal_mcu_enable_interrupts();
|
||||
common_hal_rp2pio_statemachine_deinit(&state_machine);
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("timeout waiting for flux"));
|
||||
}
|
||||
}
|
||||
|
||||
// wait for index pulse low
|
||||
while (READ_INDEX()) {
|
||||
if (time_us_64() > index_deadline_us) {
|
||||
common_hal_mcu_enable_interrupts();
|
||||
common_hal_rp2pio_statemachine_deinit(&state_machine);
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("timeout waiting for index pulse"));
|
||||
}
|
||||
}
|
||||
|
||||
pio_sm_clear_fifos(reader.pio, reader.sm);
|
||||
|
||||
// if another index doesn't show up ...
|
||||
index_deadline_us = time_us_64() + index_wait_ms * 1000;
|
||||
|
||||
int last = read_fifo(&reader);
|
||||
bool last_index = READ_INDEX();
|
||||
while (ptr != end) {
|
||||
|
||||
/* Handle index */
|
||||
bool now_index = READ_INDEX();
|
||||
|
||||
if (!now_index && last_index) {
|
||||
break;
|
||||
}
|
||||
last_index = now_index;
|
||||
|
||||
if (!data_available(&reader)) {
|
||||
// no flux is arriving? is ANY flux arriving or has a full revoulution gone by?
|
||||
if (time_us_64() > index_deadline_us) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int timestamp = read_fifo(&reader);
|
||||
int delta = last - timestamp;
|
||||
if (delta < 0) {
|
||||
delta += 65536;
|
||||
}
|
||||
delta /= 2;
|
||||
|
||||
last = timestamp;
|
||||
*ptr++ = delta > 255 ? 255 : delta;
|
||||
}
|
||||
|
||||
common_hal_mcu_enable_interrupts();
|
||||
common_hal_rp2pio_statemachine_deinit(&state_machine);
|
||||
|
||||
return ptr - (uint8_t *)buf;
|
||||
}
|
||||
|
|
@ -478,6 +478,7 @@ SRC_COMMON_HAL_ALL = \
|
|||
dotclockframebuffer/DotClockFramebuffer.c \
|
||||
dotclockframebuffer/__init__.c \
|
||||
dualbank/__init__.c \
|
||||
floppyio/__init__.c \
|
||||
frequencyio/FrequencyIn.c \
|
||||
frequencyio/__init__.c \
|
||||
imagecapture/ParallelImageCapture.c \
|
||||
|
|
|
|||
|
|
@ -40,7 +40,10 @@
|
|||
#include "py/runtime.h"
|
||||
|
||||
//| def flux_readinto(
|
||||
//| buffer: WriteableBuffer, data: digitalio.DigitalInOut, index: digitalio.DigitalInOut
|
||||
//| buffer: WriteableBuffer,
|
||||
//| data: digitalio.DigitalInOut,
|
||||
//| index: digitalio.DigitalInOut,
|
||||
//| index_wait=0.220,
|
||||
//| ) -> int:
|
||||
//| """Read flux transition information into the buffer.
|
||||
//|
|
||||
|
|
@ -52,6 +55,7 @@
|
|||
//| :param buffer: Read data into this buffer. Each element represents the time between successive zero-to-one transitions.
|
||||
//| :param data: Pin on which the flux data appears
|
||||
//| :param index: Pin on which the index pulse appears
|
||||
//| :param index_wait: Time to wait, in seconds, for the index pulse
|
||||
//| :return: The actual number of bytes of read
|
||||
//| """
|
||||
//| ...
|
||||
|
|
@ -76,7 +80,7 @@ STATIC mp_obj_t floppyio_flux_readinto(size_t n_args, const mp_obj_t *pos_args,
|
|||
|
||||
mp_int_t index_wait_ms = args[ARG_index_wait].u_obj ?
|
||||
MICROPY_FLOAT_C_FUN(round)(mp_arg_validate_type_float(args[ARG_index_wait].u_obj, MP_QSTR_index_wait) * 1000) :
|
||||
MICROPY_FLOAT_CONST(.220);
|
||||
220;
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_floppyio_flux_readinto(bufinfo.buf, bufinfo.len, data, index, index_wait_ms));
|
||||
#else
|
||||
|
|
@ -88,7 +92,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(floppyio_flux_readinto_obj, 0, floppyio_flux_readinto
|
|||
//| def mfm_readinto(
|
||||
//| buffer: WriteableBuffer,
|
||||
//| flux: ReadableBuffer,
|
||||
//| flux_t1_nominal: int,
|
||||
//| flux_t2_max: int,
|
||||
//| flux_t3_max: int,
|
||||
//| validity: bytearray | None = None,
|
||||
//| clear_validity: bool = True,
|
||||
//| ) -> int:
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "shared/timeutils/timeutils.h"
|
||||
|
||||
extern mp_obj_t struct_time_from_tm(timeutils_struct_time_t *tm);
|
||||
|
|
|
|||
|
|
@ -34,26 +34,20 @@
|
|||
#include "shared-bindings/digitalio/DigitalInOut.h"
|
||||
#endif
|
||||
|
||||
#ifndef T2_5
|
||||
#define T2_5 (FLOPPYIO_SAMPLERATE * 5 / 2 / 1000000)
|
||||
#endif
|
||||
#ifndef T3_5
|
||||
#define T3_5 (FLOPPYIO_SAMPLERATE * 7 / 2 / 1000000)
|
||||
#endif
|
||||
|
||||
#include "lib/adafruit_floppy/src/mfm_impl.h"
|
||||
|
||||
#if CIRCUITPY_DIGITALIO
|
||||
MP_WEAK
|
||||
__attribute__((optimize("O3")))
|
||||
int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index, mp_int_t index_wait_ms) {
|
||||
mp_printf(&mp_plat_print, "common_hal_floppyio_flux_readinto in %s\n", __FILE__);
|
||||
uint32_t index_mask;
|
||||
volatile uint32_t *index_port = common_hal_digitalio_digitalinout_get_reg(index, DIGITALINOUT_REG_READ, &index_mask);
|
||||
|
||||
uint32_t data_mask;
|
||||
volatile uint32_t *data_port = common_hal_digitalio_digitalinout_get_reg(data, DIGITALINOUT_REG_READ, &data_mask);
|
||||
|
||||
uint32_t index_deadline_ms = mp_hal_ticks_ms() + index_wait_ms;
|
||||
uint32_t index_deadline_ms = supervisor_ticks_ms32() + index_wait_ms;
|
||||
#undef READ_INDEX
|
||||
#undef READ_DATA
|
||||
#define READ_INDEX() (!!(*index_port & index_mask))
|
||||
|
|
@ -69,6 +63,7 @@ int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalin
|
|||
while (READ_INDEX()) { /* NOTHING */
|
||||
if (supervisor_ticks_ms32() > index_deadline_ms) {
|
||||
common_hal_mcu_enable_interrupts();
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("timeout waiting for index pulse"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue