From 7245695bc794a312409af45802d4d8de0155c86c Mon Sep 17 00:00:00 2001 From: Allen Hill Date: Sun, 10 Sep 2023 16:02:06 -0400 Subject: [PATCH] Setup timing better (fuses, clock speed, TCB clock speed) --- CMakeLists.txt | 57 ++++++++++++++++++++++++++++++++---- src/avclandrv.c | 77 ++++++++++++++++++++++++++++++------------------- src/sniffer.c | 3 ++ src/timing.h | 51 ++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 35 deletions(-) create mode 100644 src/timing.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 14d1715..8b8786b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,50 @@ cmake_minimum_required(VERSION 3.24) +include(CMakeDependentOption) set(WITH_MCU OFF) set(AVR_MCU "attiny3216") set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/avr-gcc-toolchain.cmake") -project(avr-avc-lan VERSION 1 LANGUAGES C CXX ASM) +project(avclan-mockingboard VERSION 1 LANGUAGES C CXX ASM) + +set(FREQSEL 16MHz CACHE STRING "Select the operating frequency") +set_property(CACHE FREQSEL PROPERTY STRINGS "20MHz" "16MHz") + +if(FREQSEL MATCHES "20MHz") +set(F_CPU 20000000L) +set(AVR_UPLOADTOOL_BASE_OPTIONS ${AVR_UPLOADTOOL_BASE_OPTIONS} -U osccfg:w:0x2:m) +else() +set(F_CPU 16000000L) +set(AVR_UPLOADTOOL_BASE_OPTIONS ${AVR_UPLOADTOOL_BASE_OPTIONS} -U osccfg:w:0x1:m) +endif() + +option(CLK_PRESCALE "Enable the main clock prescaler") +cmake_dependent_option(CLK_PRESCALE_DIV "Prescaler divisor" CLKCTRL_PDIV_2X_gc STRING "CLK_PRESCALE") +if(DEFINED CACHE{CLK_PRESCALE_DIV}) + set_property(CACHE CLK_PRESCALE_DIV PROPERTY STRINGS + CLKCTRL_PDIV_2X_gc + CLKCTRL_PDIV_4X_gc + CLKCTRL_PDIV_8X_gc + CLKCTRL_PDIV_16X_gc + CLKCTRL_PDIV_32X_gc + CLKCTRL_PDIV_64X_gc + CLKCTRL_PDIV_6X_gc + CLKCTRL_PDIV_10X_gc + CLKCTRL_PDIV_12X_gc + CLKCTRL_PDIV_24X_gc + CLKCTRL_PDIV_48X_gc + ) +else() +set(CLK_PRESCALE_DIV CLKCTRL_PDIV_2X_gc) +endif() + +set(TCB_CLKSEL "TCB_CLKSEL_CLKDIV2_gc" CACHE STRING "Choose the clock for TCB") +set_property(CACHE TCB_CLKSEL PROPERTY STRINGS + TCB_CLKSEL_CLKDIV1_gc + TCB_CLKSEL_CLKDIV2_gc + TCB_CLKSEL_CLKTCA_gc +) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.3") @@ -61,18 +100,24 @@ if(CMAKE_BUILD_TYPE MATCHES Debug) set(CMAKE_C_FLAGS_DEBUG "-O0 -save-temps -g -gdwarf-3 -gstrict-dwarf") endif(CMAKE_BUILD_TYPE MATCHES Debug) -add_avr_executable(sniffer +# Set startup time to 8 ms (0x4) +set(AVR_UPLOADTOOL_BASE_OPTIONS ${AVR_UPLOADTOOL_BASE_OPTIONS} -U syscfg1:w:0x4:m) + +add_avr_executable(mockingboard src/sniffer.c src/com232.c src/avclandrv.c) -target_link_options(sniffer PUBLIC +target_link_options(mockingboard PUBLIC -B "${attiny_atpack_SOURCE_DIR}/gcc/dev/${AVR_MCU}" ) -target_compile_definitions(sniffer PRIVATE - F_CPU=16000000L +target_compile_definitions(mockingboard PRIVATE + F_CPU=${F_CPU} + CLK_PRESCALE=$,0x01,0x00> + CLK_PRESCALE_DIV=${CLK_PRESCALE_DIV} + TCB_CLKSEL=${TCB_CLKSEL} ) -target_compile_options(sniffer PRIVATE +target_compile_options(mockingboard PRIVATE --param=min-pagesize=0 -ffunction-sections -fdata-sections diff --git a/src/avclandrv.c b/src/avclandrv.c index e1eff5e..5627c19 100644 --- a/src/avclandrv.c +++ b/src/avclandrv.c @@ -92,6 +92,7 @@ #include "avclandrv.h" #include "com232.h" +#include "timing.h" // Enable AVC bus Tx #define AVC_OUT_EN() \ @@ -265,12 +266,12 @@ void AVCLAN_init() { TCB0.CTRLB = TCB_CNTMODE_PW_gc; TCB0.INTCTRL = TCB_CAPT_bm; TCB0.EVCTRL = TCB_CAPTEI_bm; - TCB0.CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm; + TCB0.CTRLA = TCB_CLKSEL | TCB_ENABLE_bm; // TCB1 for send bit timing TCB1.CTRLB = TCB_CNTMODE_INT_gc; TCB1.CCMP = 0xFFFF; - TCB1.CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCB_ENABLE_bm; + TCB1.CTRLA = TCB_CLKSEL | TCB_ENABLE_bm; answerReq = cm_Null; @@ -293,34 +294,36 @@ void set_AVC_logic_for(uint8_t val, uint16_t period) { return; } -uint8_t AVCLAN_sendbit_start() { - set_AVC_logic_for(1, 1328); // 166 us @ 125 ns tick (for F_CPU = 16MHz) - set_AVC_logic_for(0, 152); // 19 us @ 125 ns tick (for F_CPU = 16MHz) - - return 1; +void AVCLAN_sendbit_start() { + set_AVC_logic_for(0, AVCLAN_STARTBIT_LOGIC_0); // 166 us + set_AVC_logic_for(1, AVCLAN_STARTBIT_LOGIC_1); // 19 us } void AVCLAN_sendbit_1() { - set_AVC_logic_for(1, 164); // 20.5 us @ 125 ns tick (for F_CPU = 16MHz) - set_AVC_logic_for(0, 152); // 19 us @ 125 ns tick (for F_CPU = 16MHz) + set_AVC_logic_for(0, AVCLAN_BIT1_LOGIC_0); // 20.5 us + set_AVC_logic_for(1, AVCLAN_BIT1_LOGIC_1); // 19 us } void AVCLAN_sendbit_0() { - set_AVC_logic_for(1, 272); // 34 us @ 125 ns tick (for F_CPU = 16MHz) - set_AVC_logic_for(0, 44); // 5.5 us @ 125 ns tick (for F_CPU = 16MHz) + set_AVC_logic_for(0, AVCLAN_BIT0_LOGIC_0); // 34 us + set_AVC_logic_for(1, AVCLAN_BIT0_LOGIC_1); // 5.5 us } void AVCLAN_sendbit_ACK() { TCB1.CNT = 0; + + // Wait for controller to begin ACK bit while (INPUT_IS_CLEAR) { - if (TCB1.CNT >= 900) - return; // max wait time + // Wait for approx the length of a bit; any longer and something has clearly + // gone wrong + if (TCB1.CNT >= AVCLAN_BIT_LENGTH) + return; } AVC_OUT_EN(); - set_AVC_logic_for(1, 272); // 34 us @ 125 ns tick (for F_CPU = 16MHz) - set_AVC_logic_for(0, 44); // 5.5 us @ 125 ns tick (for F_CPU = 16MHz) + set_AVC_logic_for(0, AVCLAN_BIT0_LOGIC_0); // 34 us + set_AVC_logic_for(1, AVCLAN_BIT0_LOGIC_1); // 5.5 us AVC_OUT_DIS(); } @@ -395,7 +398,7 @@ uint8_t AVCLAN_sendbyte(const uint8_t *byte) { ISR(TCB0_INT_vect) { // If input was set for less than 26 us (a generous half period), bit was a 1 - if (TCB0.CCMP < 208) { + if (TCB0.CCMP < (uint16_t)AVCLAN_READBIT_THRESHOLD) { READING_BYTE++; READING_PARITY++; } @@ -418,7 +421,15 @@ uint8_t AVCLAN_readbitsi(uint8_t *bits, uint8_t len) { READING_NBITS = len; sei(); - while (READING_NBITS != 0) {}; + TCB1.CNT = 0; + while (READING_NBITS != 0) { + // Duration of `len` bits + 10% + if (TCB1.CNT > (((uint16_t)AVCLAN_BIT_LENGTH * 11 * len) / 10)) { + READING_BYTE = 0; + READING_PARITY = 0; + break; // Should have finished by now; something's wrong + } + }; cli(); *bits = READING_BYTE; @@ -448,7 +459,15 @@ uint8_t AVCLAN_readbyte(uint8_t *byte) { READING_NBITS = 8; sei(); - while (READING_NBITS != 0) {}; + TCB1.CNT = 0; + while (READING_NBITS != 0) { + // Duration of byte + 10% + if (TCB1.CNT > (((uint16_t)AVCLAN_BIT_LENGTH * 11 * 8) / 10)) { + READING_BYTE = 0; + READING_PARITY = 0; + break; // Should have finished by now; something's wrong + } + }; cli(); *byte = READING_BYTE; @@ -459,20 +478,19 @@ uint8_t AVCLAN_readbyte(uint8_t *byte) { } uint8_t AVCLAN_readbit_ACK() { - set_AVC_logic_for(1, 152); // 34 us @ 125 ns tick (for F_CPU = 16MHz) - AVC_SET_LOGICAL_0(); // Replace with AVC_ReleaseLine? - AVC_OUT_DIS(); // switch to read mode - TCB1.CNT = 0; + set_AVC_logic_for(0, AVCLAN_BIT1_LOGIC_0); // 20.5 us + AVC_SET_LOGICAL_1(); + AVC_OUT_DIS(); + while (1) { - if (INPUT_IS_SET && (TCB1.CNT > 208)) - break; // Make sure INPUT is not still set from us - // Line of experimentation: Try changing TCNT0 comparison value or remove - // check entirely - if (TCB1.CNT > 300) - return 1; // Not sure if this fix is intent correct + if (INPUT_IS_SET && (TCB1.CNT > AVCLAN_READBIT_THRESHOLD)) + break; // ACK + if (TCB1.CNT > AVCLAN_BIT_LENGTH) + return 1; // NAK } + // Check/wait in case we get here before peripheral finishes ACK bit while (INPUT_IS_SET) {} AVC_OUT_EN(); // back to write mode return 0; @@ -669,7 +687,8 @@ uint8_t AVCLAN_sendframe(const AVCLAN_frame_t *frame) { TCB1.CNT = 0; do { while (INPUT_IS_CLEAR) { - if (TCB1.CNT >= 900) + // Wait for 120% of a bit length + if (TCB1.CNT >= (uint16_t)(AVCLAN_BIT_LENGTH * 12 / 10)) break; } if (TCB1.CNT > 864) diff --git a/src/sniffer.c b/src/sniffer.c index 0de74a9..cdecc92 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "avclandrv.h" @@ -217,6 +218,8 @@ void Setup() { printAllFrames = 1; echoCharacters = 1; + _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, (CLK_PRESCALE | CLK_PRESCALE_DIV)); + general_GPIO_init(); // Setup RTC as 1 sec periodic timer diff --git a/src/timing.h b/src/timing.h new file mode 100644 index 0000000..8091796 --- /dev/null +++ b/src/timing.h @@ -0,0 +1,51 @@ +#ifndef _TIMING_HPP_ +#define _TIMING_HPP_ + +#if CLK_PRESCALE == 0x01 +#error "Not implemented" +#else + +#if F_CPU == 20000000L +#define CPU_CYCLE 50 +#elif F_CPU == 16000000L +#define CPU_CYCLE 62.5 +#else +#error "Not implemented" +#endif + +#ifndef TCB_CLKSEL_CLKDIV1_gc +#define TCB_CLKSEL_CLKDIV1_gc (0x00 << 1) +#endif + +#ifndef TCB_CLKSEL_CLKDIV2_gc +#define TCB_CLKSEL_CLKDIV2_gc (0x01 << 1) +#endif + +#ifndef TCB_CLKSEL_CLKTCA_gc +#define TCB_CLKSEL_CLKTCA_gc (0x02 << 1) +#endif + +#if TCB_CLKSEL == TCB_CLKSEL_CLKDIV1_gc +#define TCB_TICK (CPU_CYCLE) +#elif TCB_CLKSEL == TCB_CLKSEL_CLKDIV2_gc +#define TCB_TICK (CPU_CYCLE * 2) +#elif TCB_CLKSEL == TCB_CLKSEL_CLKTCA_gc +#error "Not implemented" +#endif + +#define AVCLAN_STARTBIT_LOGIC_0 (166e3 / TCB_TICK) +#define AVCLAN_STARTBIT_LOGIC_1 (19e3 / TCB_TICK) + +#define AVCLAN_BIT1_LOGIC_0 (20.5e3 / TCB_TICK) +#define AVCLAN_BIT1_LOGIC_1 (19e3 / TCB_TICK) + +#define AVCLAN_BIT0_LOGIC_0 (34e3 / TCB_TICK) +#define AVCLAN_BIT0_LOGIC_1 (5.5e3 / TCB_TICK) + +#define AVCLAN_READBIT_THRESHOLD (26e3 / TCB_TICK) + +#define AVCLAN_BIT_LENGTH (39.5e3 / TCB_TICK) + +#endif + +#endif \ No newline at end of file