From d14554c0ac932d515c301a206f6eb45efa9be1ea Mon Sep 17 00:00:00 2001 From: Matt Jenkins Date: Thu, 4 Sep 2025 14:42:58 +0100 Subject: [PATCH] Full track streaming and CLI interface --- firmware/Test/Test.ino | 363 ++++++++++++++++++++++++++++------- firmware/Test/datastream.pio | 18 +- 2 files changed, 298 insertions(+), 83 deletions(-) diff --git a/firmware/Test/Test.ino b/firmware/Test/Test.ino index 93bcc7e..e8a0a8c 100644 --- a/firmware/Test/Test.ino +++ b/firmware/Test/Test.ino @@ -1,51 +1,72 @@ -/* - * PIO - * - * - * Fifo format - * 19 bits of address - * 8 bits of current data value - * 3 bits of head number - * 2 bit of pin data - * - * Shift 1 bit from OSR into pins - * Shift 11 bits from OSR into ISR - * Shift 3 bits from pins into ISR - * - * PULL block - * OUT pins 1 - * OUT ISR 11 - * IN pin 3 - * PUSH noblock - * - * Software: - * Write to fifo data, head and current bit - * Read from fifo. - * Test write bit - * If set, set or clear affected bit - * Shift data to 8 bits and replace in buffer - */ +#include #include "datastream.h" +#define SECTOR_128 0 +#define SECTOR_256 1 +#define SECTOR_512 2 +#define SECTOR_1024 3 + + static PIOProgram datastreamPgm(&datastream_program); PIO pio; int sm; int offset; -uint16_t header_crc; #define POLY16 0x1021 #define POLY32 0xa00805 -static inline void w() { - while(pio_sm_is_tx_fifo_full(pio, sm)); -} +#define CQ16(V, C) C = crc16(V, C); queue(mfm_encode(V)) +#define CQ32(V, C) C = crc32(V, C); queue(mfm_encode(V)) + +#define NUM_SECTORS 17 + +#define TRACK_SIZE (512 * NUM_SECTORS) + +uint8_t *track_data; + + +struct disk_format { + uint16_t cyls; + uint8_t heads; + uint8_t sectors; + uint8_t sector_size; + uint8_t track_pregap; + uint8_t track_postgap; + uint8_t header_postgap; + uint8_t data_postgap; + float data_rate; + + // Calculated data - not to be filled. + + uint32_t tlen; + uint32_t slen; + uint32_t idx_ts; + uint32_t idx_period; + float clock_div; +}; + + +struct disk_format RD54 = { + 1225, // Cyl + 15, // Heads + 17, // Sectors, + SECTOR_512, // Bytes per sector + 151, // Track pregap + 151, // Track postgap + 16, // Header postgap + 50, // Data postgap + 5000000, // Data Rate +}; + + +struct disk_format *format; + void bindump(uint16_t v) { for (int i = 0; i < 16; i++) { - Serial.print((v & 0x8000) ? "1" : "0"); v <<= 1; } } @@ -105,29 +126,225 @@ uint16_t mfm_encode(uint8_t b) { uint16_t out = 0; - //Serial.print(">>> "); - //Serial.println(b, HEX); - for (int i = 0; i < 8; i++) { out <<= 2; - //Serial.println(b, BIN); out |= mfm_encode_bit(b & 0x80); b <<= 1; } - //Serial.print("Last bit: "); - //Serial.println(last_bit); - - //Serial.print("Output: "); - //Serial.println(out, BIN); - return out; } -void csend(uint8_t v) { - w(); - pio->txf[sm] = mfm_encode(v); - header_crc = crc16(v, header_crc); +static inline void queue(uint16_t val) { + while(pio_sm_is_tx_fifo_full(pio, sm)); + pio->txf[sm] = val; +} + +void sync() { + uint16_t sync = mfm_encode(0xA1); + sync &= 0b1111111111011111; + queue(sync); + +} + +void zero_pad() { + queue(mfm_encode(0x00)); +} + +void send_header(uint16_t cyl, uint8_t head, uint8_t sector, uint8_t size) { + uint16_t header_crc = 0xFFFF; + + zero_pad(); + + sync(); + header_crc = crc16(0xA1, header_crc); + + CQ16(0xFE, header_crc); + CQ16(cyl & 0xFF, header_crc); + CQ16(((cyl >> 4) & 0xF0) | (head & 0x0F), header_crc); + CQ16(sector, header_crc); + CQ16(size, header_crc); + + queue(mfm_encode((header_crc >> 8) & 0xFF)); + queue(mfm_encode(header_crc & 0xFF)); + + zero_pad(); +} + +void send_data(uint8_t *data, uint16_t len) { + uint32_t data_crc = 0xFFFFFFFF; + + zero_pad(); + sync(); + data_crc = crc32(0xA1, data_crc); + + CQ32(0xFB, data_crc); + + for (int i = 0; i < len; i++) { + CQ32(data[i], data_crc); + } + + queue(mfm_encode((data_crc >> 24) & 0xFF)); + queue(mfm_encode((data_crc >> 16) & 0xFF)); + queue(mfm_encode((data_crc >> 8) & 0xFF)); + queue(mfm_encode(data_crc & 0xFF)); + + zero_pad(); + +} + +void send_sector(uint16_t cyl, uint8_t head, uint8_t sector, uint8_t size, uint8_t *data, uint8_t pad) { + send_header(cyl, head, sector, size); + + for (int i = 0; i < pad; i++) { + zero_pad(); + } + + uint16_t len = 0x80 << size; + send_data(data, len); +} + + +void second_cpu_thread() { + while (1) { + for (int i = 0; i < format->track_postgap; i++) { + zero_pad(); + } + format->idx_period = micros() - format->idx_ts; + format->idx_ts = micros(); + digitalWrite(13, LOW); + zero_pad(); + digitalWrite(13, HIGH); + for (int i = 0; i < format->track_pregap; i++) { + zero_pad(); + } + + for (int sector = 0; sector < format->sectors; sector++) { + + send_sector(0, 0, sector, format->sector_size, track_data + (sector * format->slen), format->header_postgap); + + for (int i = 0; i < format->data_postgap; i++) { + zero_pad(); + } + } + } +} + + +CLI_COMMAND(cli_status) { + uint32_t sector_bytes = 8 + format->slen + 6 + format->header_postgap + format->data_postgap + 4; + uint32_t total_clocks = ((sector_bytes * format->sectors) + format->track_pregap + format->track_postgap + 1) * 8; + + float rpm = (format->data_rate / total_clocks) * 60.0; + + dev->print("Cylinders: "); + dev->println(format->cyls); + dev->print("Heads: "); + dev->println(format->heads); + dev->print("Sectors: "); + dev->println(format->sectors); + dev->print("Sector Size: "); + dev->print(0x80 << format->sector_size); + dev->println(" bytes"); + + dev->println(); + dev->print("Track Pregap: "); + dev->print(format->track_pregap); + dev->println(" bytes"); + + dev->print("Track Postgap: "); + dev->print(format->track_postgap); + dev->println(" bytes"); + + dev->print("Header Postgap: "); + dev->print(format->header_postgap); + dev->println(" bytes"); + + dev->print("Data Postgap: "); + dev->print(format->data_postgap); + dev->println(" bytes"); + + dev->println(); + + dev->print("Total clocks per track: "); + dev->println(total_clocks); + + dev->print("Calculated RPM: "); + dev->println(rpm); + + dev->print("Actual RPM: "); + float p = format->idx_period / 1000000.0; + float f = 1.0 / p; + float r = f * 60; + dev->println(r); + + dev->print("Requested Data Rate: "); + dev->print(format->data_rate); + dev->println("MHz"); + dev->print("Actual Data Rate: "); + dev->print(F_CPU / format->clock_div / 20.0); + dev->println("MHz"); + + dev->print("Clock divider: "); + dev->println(format->clock_div); + + return 0; +} + +CLI_COMMAND(cli_set) { + + if (argc != 3) { + dev->println("Usage: set "); + + dev->println("Possible items:"); + dev->println(" track_pregap"); + dev->println(" track_posthap"); + dev->println(" header_postgap"); + dev->println(" data_postgap"); + dev->println(" data_rate"); + return 10; + } + + if (strcmp(argv[1], "track_pregap") == 0) { + format->track_pregap = strtoul(argv[2], NULL, 10); + return 0; + } + + if (strcmp(argv[1], "track_postgap") == 0) { + format->track_postgap = strtoul(argv[2], NULL, 10); + return 0; + } + + if (strcmp(argv[1], "header_postgap") == 0) { + format->header_postgap = strtoul(argv[2], NULL, 10); + return 0; + } + + if (strcmp(argv[1], "data_postgap") == 0) { + format->data_postgap = strtoul(argv[2], NULL, 10); + return 0; + } + + if (strcmp(argv[1], "data_rate") == 0) { + float r = strtof(argv[2], NULL); + float cd = F_CPU / r / 20.0; + if (cd < 1) { + dev->println("Data rate too high for the CPU clock"); + return 10; + } + format->data_rate = r; + format->clock_div = cd; + pio_sm_set_clkdiv(pio, sm, format->clock_div); + return 0; + } + + + dev->println("Possible items:"); + dev->println(" track_pregap"); + dev->println(" track_posthap"); + dev->println(" header_postgap"); + dev->println(" data_postgap"); + return 10; } void setup() { @@ -138,37 +355,35 @@ void setup() { pio->txf[sm] = mfm_encode(0x00); pinMode(13, OUTPUT); - digitalWrite(13, LOW); + digitalWrite(13, HIGH); Serial.begin(115200); + + format = &RD54; + + format->slen = 0x80 << format->sector_size; + format->tlen = format->slen * format->sectors; + + track_data = (uint8_t *)malloc(format->tlen); + + for (int i = 0; i < format->tlen; i++) { + track_data[i] = rand(); + } + + + format->clock_div = F_CPU / format->data_rate / 20.0; + pio_sm_set_clkdiv(pio, sm, format->clock_div); + + multicore_launch_core1(second_cpu_thread); + + Serial.begin(115200); + CLI.setDefaultPrompt("RTmFM> "); + CLI.addClient(Serial); + + CLI.addCommand("status", cli_status); + CLI.addCommand("set", cli_set); } void loop() { - delay(1); - - digitalWrite(13, HIGH); - digitalWrite(13, LOW); - - last_bit = 0; - w(); - pio->txf[sm] = mfm_encode(0x00); - - header_crc = 0xFFFF; - header_crc = crc16(0xA1, header_crc); - uint16_t sync = mfm_encode(0xA1); - //sync &= 0b1111101111111111; - sync &= 0b1111111111011111; - - pio->txf[sm] = sync; - csend(0xFE); - csend(0x00); - csend(0x00); - csend(0x03); - csend(0x02); - w(); - pio->txf[sm] = mfm_encode(header_crc >> 8); - w(); - pio->txf[sm] = mfm_encode(header_crc & 0xff); - w(); - pio->txf[sm] = mfm_encode(0x00); + CLI.process(); } diff --git a/firmware/Test/datastream.pio b/firmware/Test/datastream.pio index c8ba6b8..5e40cff 100644 --- a/firmware/Test/datastream.pio +++ b/firmware/Test/datastream.pio @@ -11,16 +11,16 @@ public start: SET Y,6 loop: - OUT PINS,1 [14] - SET PINS,0 [14] - OUT PINS,1 [14] - SET PINS,0 [13] + OUT PINS,1 [4] + SET PINS,0 [4] + OUT PINS,1 [4] + SET PINS,0 [3] JMP Y-- loop - OUT PINS,1 [14] - SET PINS,0 [14] - OUT PINS,1 [14] - SET PINS,0 [11] + OUT PINS,1 [4] + SET PINS,0 [4] + OUT PINS,1 [4] + SET PINS,0 [1] .wrap @@ -33,7 +33,7 @@ static inline void datastream_program_init(PIO pio, uint sm, uint offset) { pio_sm_config c = datastream_program_get_default_config(offset); sm_config_set_out_shift(&c, false, false, 0); sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); - sm_config_set_clkdiv(&c, 1.0); + sm_config_set_clkdiv(&c, 3.0); sm_config_set_out_pin_base(&c, 12); sm_config_set_out_pin_count(&c, 1); sm_config_set_set_pin_base(&c, 12);