From cad23aa814eeb27c8842f6931612d3e06967b34c Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Mon, 30 Dec 2019 21:06:18 +0100 Subject: [PATCH 01/14] 32U4 support: JICE_io and jtag2updi.cpp changed Modified JICE_io and jtag2updi to compile for 32U4. Failed to transfer files though. USB port shows up, HEX reply to command as expected, but couldn't program, yet. --- source/JICE_io.cpp | 17 ++++++++++++++++- source/JICE_io.h | 5 ++++- source/jtag2updi.cpp | 35 ++++++++++++++++++++++++++++------- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/source/JICE_io.cpp b/source/JICE_io.cpp index 6556b98..a932d07 100644 --- a/source/JICE_io.cpp +++ b/source/JICE_io.cpp @@ -6,7 +6,8 @@ */ // Includes -#include +#include +//#include #include "JICE_io.h" #include "sys.h" @@ -21,6 +22,9 @@ uint8_t JICE_io::put(char c) { #ifdef __AVR_ATmega16__ loop_until_bit_is_set(UCSRA, UDRE); return UDR = c; +#elif __AVR_ATmega32U4__ + SERIALCOM.write(c); //test 32U4 + return c; //test 32U4 #else loop_until_bit_is_set(UCSR0A, UDRE0); return UDR0 = c; @@ -31,6 +35,10 @@ uint8_t JICE_io::get(void) { #ifdef __AVR_ATmega16__ loop_until_bit_is_set(UCSRA, RXC); /* Wait until data exists. */ return UDR; +#elif __AVR_ATmega32U4__ + //while (!Serial.available()); //test 32U4 + uint8_t c = SERIALCOM.read(); //test 32U4 + return c; //test 32U4 #else loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ return UDR0; @@ -48,6 +56,9 @@ void JICE_io::init(void) { UCSRB = (1< #include "JTAG2.h" +#warning "modify this to match your USB serial port name" +#define SERIALCOM Serial + namespace JICE_io { // Function prototypes uint8_t put(char c); @@ -21,4 +24,4 @@ namespace JICE_io { void set_baud(JTAG2::baud_rate rate); } -#endif /* JICE_IO_H_ */ \ No newline at end of file +#endif /* JICE_IO_H_ */ diff --git a/source/jtag2updi.cpp b/source/jtag2updi.cpp index 92ccde4..a3f8eed 100644 --- a/source/jtag2updi.cpp +++ b/source/jtag2updi.cpp @@ -6,6 +6,9 @@ */ // Includes +#include +//#include "USBAPI.h" + #include "sys.h" #include "updi_io.h" #include "JICE_io.h" @@ -14,19 +17,37 @@ /* Internal stuff */ namespace { // Prototypes - void setup(); - void loop(); + void setup2(); + void loop2(); } +// Declared weak in Arduino.h to allow user redefinitions. +int atexit(void (* /*func*/ )()) { return 0; } + +// Weak empty variant initialization function. +// May be redefined by variant files. +void initVariant() __attribute__((weak)); +void initVariant() { } + +void setupUSB() __attribute__((weak)); +void setupUSB() { } + int main(void) { - setup(); - loop(); + init(); + + initVariant(); + + #if defined(USBCON) + USBDevice.attach(); + #endif + setup2(); + loop2(); } /* Internal stuff */ namespace { - inline void setup() { + inline void setup2() { /* Initialize MCU */ SYS::init(); @@ -36,7 +57,7 @@ namespace { } - inline void loop() { + inline void loop2() { while (1) { // Receive command @@ -88,4 +109,4 @@ namespace { JTAG2::delay_exec(); } } -} \ No newline at end of file +} From c3757f69fce8517391d5aad5fc661d5fe3d49482 Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Sun, 2 Feb 2020 12:26:58 +0100 Subject: [PATCH 02/14] Add files via upload Support for Arduino devices using HW_SERIAL for communication with PC, UART used for UPDI. --- source/JICE_io.cpp | 59 ++++++++---- source/JICE_io.h | 4 +- source/JTAG2.h | 2 +- source/jtag2updi.cpp | 42 +++++---- source/sys.cpp | 48 +++++++--- source/sys.h | 219 +++++++++++++++++++++++++++++++------------ source/updi_io.cpp | 67 ++++++++++++- 7 files changed, 324 insertions(+), 117 deletions(-) diff --git a/source/JICE_io.cpp b/source/JICE_io.cpp index a932d07..991148a 100644 --- a/source/JICE_io.cpp +++ b/source/JICE_io.cpp @@ -7,14 +7,14 @@ // Includes #include -//#include +#include #include "JICE_io.h" #include "sys.h" namespace { // *** Baud rate lookup table for UBRR0 register *** // Indexed by valid values for PARAM_BAUD_RATE_VAL (defined in JTAG2.h) - FLASH baud_tbl[8] = {baud(2400), baud(4800), baud(9600), baud(19200), baud(38400), baud(57600), baud(115200), baud(14400)}; + FLASH baud_tbl[8] = {baud_reg_val(2400), baud_reg_val(4800), baud_reg_val(9600), baud_reg_val(19200), baud_reg_val(38400), baud_reg_val(57600), baud_reg_val(115200), baud_reg_val(14400)}; } // Functions @@ -22,9 +22,14 @@ uint8_t JICE_io::put(char c) { #ifdef __AVR_ATmega16__ loop_until_bit_is_set(UCSRA, UDRE); return UDR = c; -#elif __AVR_ATmega32U4__ - SERIALCOM.write(c); //test 32U4 - return c; //test 32U4 +#elif defined XTINY + loop_until_bit_is_set(HOST_USART.STATUS, USART_DREIF_bp); + return HOST_USART.TXDATAL = c; +#elif defined __AVR_ATmega32U4__ + // wait for Serial to be active + while (!SERIALCOM){ SYS::LED_blink(2, 1, 100);}; + SERIALCOM.write(c); //test 32U4 + return c; //test 32U4 #else loop_until_bit_is_set(UCSR0A, UDRE0); return UDR0 = c; @@ -35,10 +40,13 @@ uint8_t JICE_io::get(void) { #ifdef __AVR_ATmega16__ loop_until_bit_is_set(UCSRA, RXC); /* Wait until data exists. */ return UDR; -#elif __AVR_ATmega32U4__ - //while (!Serial.available()); //test 32U4 - uint8_t c = SERIALCOM.read(); //test 32U4 - return c; //test 32U4 +#elif defined XTINY + loop_until_bit_is_set(HOST_USART.STATUS, USART_RXCIF_bp); /* Wait until data exists. */ + return HOST_USART.RXDATAL; +#elif defined __AVR_ATmega32U4__ + //while (!Serial.available()); //test 32U4 + uint8_t c = SERIALCOM.read(); //test 32U4 + return c; //test 32U4 #else loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ return UDR0; @@ -51,19 +59,29 @@ void JICE_io::init(void) { UCSRA = (1< +//#include #include "JTAG2.h" +#if defined __AVR_ATmega32U4__ #warning "modify this to match your USB serial port name" #define SERIALCOM Serial +#endif namespace JICE_io { // Function prototypes diff --git a/source/JTAG2.h b/source/JTAG2.h index e8fb172..3d48be4 100644 --- a/source/JTAG2.h +++ b/source/JTAG2.h @@ -154,4 +154,4 @@ namespace JTAG2 { -#endif /* STK_H_ */ \ No newline at end of file +#endif /* STK_H_ */ diff --git a/source/jtag2updi.cpp b/source/jtag2updi.cpp index a3f8eed..ea1bf9c 100644 --- a/source/jtag2updi.cpp +++ b/source/jtag2updi.cpp @@ -6,8 +6,22 @@ */ // Includes -#include -//#include "USBAPI.h" +#if defined __AVR_ATmega32U4__ + #include + #include "USBAPI.h" + +// Declared weak in Arduino.h to allow user redefinitions. + int atexit(void (* /*func*/ )()) { return 0; } + +// Weak empty variant initialization function. +// May be redefined by variant files. + void initVariant() __attribute__((weak)); + void initVariant() { } + + void setupUSB() __attribute__((weak)); + void setupUSB() { } + +#endif #include "sys.h" #include "updi_io.h" @@ -21,26 +35,16 @@ namespace { void loop2(); } -// Declared weak in Arduino.h to allow user redefinitions. -int atexit(void (* /*func*/ )()) { return 0; } - -// Weak empty variant initialization function. -// May be redefined by variant files. -void initVariant() __attribute__((weak)); -void initVariant() { } - -void setupUSB() __attribute__((weak)); -void setupUSB() { } - int main(void) { - init(); - - initVariant(); + #if defined __AVR_ATmega32U4__ + init(); + initVariant(); + #endif - #if defined(USBCON) - USBDevice.attach(); - #endif + #if defined(USBCON) + USBDevice.attach(); + #endif setup2(); loop2(); } diff --git a/source/sys.cpp b/source/sys.cpp index 2b0a851..e651da0 100644 --- a/source/sys.cpp +++ b/source/sys.cpp @@ -14,18 +14,30 @@ void SYS::init(void) { #ifndef __AVR_ATmega16__ -# if defined(ARDUINO_AVR_LARDU_328E) - clock_prescale_set ( (clock_div_t) __builtin_log2(32000000UL / F_CPU)); +# if defined HW_SERIAL +// skip all init, UART used +# elif defined XTINY + // Set clock speed to maximum (default 20MHz, or 16MHz set by fuse) + _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); + /* Disable unused peripherals */ + //ToDo +# else +# if defined(ARDUINO_AVR_LARDU_328E) + clock_prescale_set ( (clock_div_t) __builtin_log2(32000000UL / F_CPU)); +# endif + /* Disable digital input buffers on port C */ + DIDR0 = 0x3F; + /* Disable unused peripherals */ + ACSR = 1 << ACD; // turn off comparator +# endif //HW_SERIAL, XTINY +# ifndef HW_SERIAL + /* Enable all UPDI port pull-ups */ + PORT(UPDI_PORT) = 0xFF; # endif - /* Disable digital input buffers on port C */ - DIDR0 = 0x3F; - /* Enable all UPDI port pull-ups */ - PORT(UPDI_PORT) = 0xFF; - /* Enable all LED port pull-ups, except for the LED pin */ - PORT(LED_PORT) = 0xFF - (1 << LED_PIN); - /* Disable unused peripherals */ - ACSR = 1 << ACD; // turn off comparator - + /* Enable LED */ + //PORT(LED_PORT) |= (1 << LED_PIN); + /* Enable all LED port pull-ups, except for the LED pin */ + PORT(LED_PORT) = 0xFF - (1 << LED_PIN); #else /* No interrupts */ sei(); @@ -50,7 +62,7 @@ void SYS::init(void) { OCR1B = 0x0000; TCCR1A = 0x0000; TCCR1B = 0x0000; -#endif +#endif //__AVR_ATmega16__ } @@ -61,3 +73,15 @@ void SYS::setLED(void){ void SYS::clearLED(void){ PORT(LED_PORT) &= ~(1 << LED_PIN); } + +const int LED[] = {3, 6, 9, 14, 10}; +//const int blinklength_ms = 1000; +//unsigned long milli = 0UL; +void SYS::LED_blink (int led_no, int led_blinks, int length_ms) { + for (int i=0; i +#include //for recognizing HW_SERIAL + +#warning "modify this to match your USB serial port name" +#define SERIALCOM Serial + +// default UART is Serial (HAVE_SERIAL), look for additional ones +// see if additional HW-SERIAL is available, take biggest for UDPI as default +#if defined(HAVE_HWSERIAL3) +# define HW_SERIAL Serial3 +#elif defined(HAVE_HWSERIAL2) +# define HW_SERIAL Serial2 +#elif defined(HAVE_HWSERIAL1) +# define HW_SERIAL Serial1 +#endif -# ifndef LED_PIN -# define LED_PIN 7 -# endif +//#define HW_SERIAL Serial1 -# ifndef UPDI_IO_TYPE -# define UPDI_IO_TYPE 2 -# endif +// if HW_SERIAL exists change UDPI mode +#if defined(HW_SERIAL) +# define UPDI_IO_TYPE 3 #endif -// Default configuration (suitable for ATmega 328P and similar devices @16MHz) -#ifndef UPDI_PORT -#define UPDI_PORT D +// See if we are compiling for an UPDI chip (xmega3 core) +#if __AVR_ARCH__ == 103 +# define XTINY #endif -#ifndef UPDI_PIN -#define UPDI_PIN 6 +// Auxiliary Macros +#define CONCAT(A,B) A##B +#if defined XTINY +# define PIN(x) CONCAT(VPORT,x).IN +# define PORT(x) CONCAT(VPORT,x).OUT +# define DDR(x) CONCAT(VPORT,x).DIR +#else +# define PIN(x) CONCAT(PIN,x) +# define PORT(x) CONCAT(PORT,x) +# define DDR(x) CONCAT(DDR,x) #endif -#ifndef LED_PORT -#define LED_PORT B -#endif +// Configuration for AVR with additional UART - only LED pin needed, UDPI via UART +#if defined(HW_SERIAL) +// Leonardo / ProMicro PortB, Pin5 = D9 +# ifndef LED_PORT +# define LED_PORT B +# endif -#ifndef LED_PIN -#define LED_PIN 5 +# ifndef LED_PIN +# define LED_PIN 5 +# endif +// Configuration for Arduino Mega +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +# ifndef UPDI_PORT +# define UPDI_PORT D +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 3 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 7 +# endif + +# ifndef UPDI_IO_TYPE +# define UPDI_IO_TYPE 2 +# endif + +// Configuration for AVR-0/1 +#elif defined XTINY +# ifndef UPDI_PORT +# define UPDI_PORT B +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 0 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 1 +# endif + +# ifndef UPDI_IO_TYPE +# define UPDI_IO_TYPE 2 +# endif +// These are currently used only for AVR-0/1 chips +// Select which USART peripheral is being used for host PC communication +// Also, indicate the port/pin of the HOST_USART Tx pin +# ifndef HOST_USART +# define HOST_USART USART0 +# endif + +# ifndef HOST_TX_PORT +# define HOST_TX_PORT B +# endif + +# ifndef HOST_TX_PIN +# define HOST_TX_PIN 2 +# endif + +// Default configuration (suitable for ATmega 328P and similar devices @16MHz) +#else +# ifndef UPDI_PORT +# define UPDI_PORT D +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 6 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 5 +# endif #endif + #ifndef F_CPU -#define F_CPU 16000000U +# define F_CPU 16000000U #endif #ifndef UPDI_BAUD -#define UPDI_BAUD 225000U // (max 225000 min approx. F_CPU/100) +# define UPDI_BAUD 225000U // (max 225000 min approx. F_CPU/100) #endif /* @@ -72,41 +154,54 @@ * Slightly slower upload speed for a given UPDI_BAUD value. Download speed is the same. */ #ifndef UPDI_IO_TYPE -#define UPDI_IO_TYPE 2 +# define UPDI_IO_TYPE 2 #endif // Flash constants class -#include -#define FLASH const PROGMEM flash - -template -class flash { - private: - const T data; - - public: - // normal constructor - constexpr flash (T _data) : data(_data) {} - // default constructor - constexpr flash () : data(0) {} - - operator T() const { - switch (sizeof(T)) { - case 1: return pgm_read_byte(&data); - case 2: return pgm_read_word(&data); - case 4: return pgm_read_dword(&data); +#if defined XTINY + template + using FLASH = const T; +#else +# include +# define FLASH const PROGMEM flash + + template + class flash { + private: + const T data; + + public: + // normal constructor + constexpr flash (T _data) : data(_data) {} + // default constructor + constexpr flash () : data(0) {} + + operator T() const { + switch (sizeof(T)) { + case 1: return pgm_read_byte(&data); + case 2: return pgm_read_word(&data); + case 4: return pgm_read_dword(&data); + } } - } -}; + }; +#endif -constexpr unsigned int baud(unsigned long b) { - return F_CPU/(b*8.0) - 0.5; -} +#if defined XTINY + // Note: adapted from MicroChip appnote TB3216 "Getting Started with USART" + constexpr unsigned int baud_reg_val(unsigned long baud) { + return (F_CPU * 64.0) / (16.0 * baud) + 0.5; + } +#else + constexpr unsigned int baud_reg_val(unsigned long baud) { + return F_CPU/(baud * 8.0) - 0.5; + } +#endif namespace SYS { void init(void); void setLED(void); void clearLED(void); + void LED_blink (int led_no, int led_blinks, int length_ms); } #endif /* SYS_H_ */ diff --git a/source/updi_io.cpp b/source/updi_io.cpp index f47c459..2ad45fb 100644 --- a/source/updi_io.cpp +++ b/source/updi_io.cpp @@ -5,8 +5,8 @@ * Author: JMR_2 */ - - + + // Includes #include #include "updi_io.h" @@ -220,5 +220,64 @@ namespace { } } - -#endif //__AVR_ATmega16__ + +#endif //UPDI_IO_TYPE == 1 + +#if UPDI_IO_TYPE == 3 +#include + +// Functions +/* Sends regular characters through the UPDI link */ +uint8_t UPDI_io::put(char c) { + HW_SERIAL.write(c); + HW_SERIAL.flush(); + //delayMicroseconds(10); + long start = millis(); + while (!HW_SERIAL.available() && millis() - start < 20) {} + char d = HW_SERIAL.read(); + if (c != d) { + // Serial.println("echo failed! " + String(d, HEX)); + } + return c; +} + +/* Sends special sequences through the UPDI link */ +uint8_t UPDI_io::put(ctrl c) +{ + HW_SERIAL.begin(300, SERIAL_8N1); + switch (c) { + case double_break: + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + break; + case single_break: + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + break; + default: + break; + } + delay(15); + while (HW_SERIAL.available()) { + HW_SERIAL.read(); + } + HW_SERIAL.begin(230400, SERIAL_8E2); + return 0; +} + +uint8_t UPDI_io::get() { + uint8_t c; + while (!HW_SERIAL.available()) {} + c = HW_SERIAL.read(); + //delayMicroseconds(5); + //Serial.println("get! " + String(c, HEX)); + return c; +} + +void UPDI_io::init(void) +{ + HW_SERIAL.begin(230400, SERIAL_8E2); +} +#endif //UPDI_IO_TYPE == 3 From 27d97f7fd38657c9def6a110faa09afd2516d8e1 Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 4 Feb 2020 08:42:20 +0100 Subject: [PATCH 03/14] Add files via upload Separated UPDI for type1 (bitbang) and type3 (UART). Changed to more 'relaxed' timings for using UPDI. --- source/UPDI_lo_lvl.h | 10 ++++-- source/jtag2updi.cpp | 6 +++- source/sys.cpp | 4 +-- source/updi_io.cpp | 59 --------------------------------- source/updi_io_uart.cpp | 73 +++++++++++++++++++++++++++++++++++++++++ source/updi_io_uart.h | 25 ++++++++++++++ 6 files changed, 112 insertions(+), 65 deletions(-) create mode 100644 source/updi_io_uart.cpp create mode 100644 source/updi_io_uart.h diff --git a/source/UPDI_lo_lvl.h b/source/UPDI_lo_lvl.h index f255f91..7417fcb 100644 --- a/source/UPDI_lo_lvl.h +++ b/source/UPDI_lo_lvl.h @@ -9,9 +9,13 @@ #ifndef UPDI_LO_LVL_H_ #define UPDI_LO_LVL_H_ -#include #include "sys.h" -#include "updi_io.h" +#if UPDI_IO_TYPE==3 + #include "updi_io_uart.h" +#else + #include "updi_io.h" +#endif +//#include "updi_io.h" namespace UPDI { // UPDI registers @@ -77,4 +81,4 @@ namespace UPDI { } } -#endif /* UPDI_LO_LVL_H_ */ \ No newline at end of file +#endif /* UPDI_LO_LVL_H_ */ diff --git a/source/jtag2updi.cpp b/source/jtag2updi.cpp index ea1bf9c..4347e97 100644 --- a/source/jtag2updi.cpp +++ b/source/jtag2updi.cpp @@ -24,7 +24,11 @@ #endif #include "sys.h" -#include "updi_io.h" +#if UPDI_IO_TYPE==3 + #include "updi_io_uart.h" +#else + #include "updi_io.h" +#endif #include "JICE_io.h" #include "JTAG2.h" diff --git a/source/sys.cpp b/source/sys.cpp index e651da0..67ed433 100644 --- a/source/sys.cpp +++ b/source/sys.cpp @@ -74,7 +74,7 @@ void SYS::clearLED(void){ PORT(LED_PORT) &= ~(1 << LED_PIN); } -const int LED[] = {3, 6, 9, 14, 10}; +const int LED[] = {3, 6, 9, 14, 10, 5}; //const int blinklength_ms = 1000; //unsigned long milli = 0UL; void SYS::LED_blink (int led_no, int led_blinks, int length_ms) { @@ -84,4 +84,4 @@ void SYS::LED_blink (int led_no, int led_blinks, int length_ms) { digitalWrite(LED[led_no], LOW); // set the RX LED ON delay(length_ms); } -} \ No newline at end of file +} diff --git a/source/updi_io.cpp b/source/updi_io.cpp index 2ad45fb..8e9db80 100644 --- a/source/updi_io.cpp +++ b/source/updi_io.cpp @@ -222,62 +222,3 @@ namespace { #endif //UPDI_IO_TYPE == 1 - -#if UPDI_IO_TYPE == 3 -#include - -// Functions -/* Sends regular characters through the UPDI link */ -uint8_t UPDI_io::put(char c) { - HW_SERIAL.write(c); - HW_SERIAL.flush(); - //delayMicroseconds(10); - long start = millis(); - while (!HW_SERIAL.available() && millis() - start < 20) {} - char d = HW_SERIAL.read(); - if (c != d) { - // Serial.println("echo failed! " + String(d, HEX)); - } - return c; -} - -/* Sends special sequences through the UPDI link */ -uint8_t UPDI_io::put(ctrl c) -{ - HW_SERIAL.begin(300, SERIAL_8N1); - switch (c) { - case double_break: - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - break; - case single_break: - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - break; - default: - break; - } - delay(15); - while (HW_SERIAL.available()) { - HW_SERIAL.read(); - } - HW_SERIAL.begin(230400, SERIAL_8E2); - return 0; -} - -uint8_t UPDI_io::get() { - uint8_t c; - while (!HW_SERIAL.available()) {} - c = HW_SERIAL.read(); - //delayMicroseconds(5); - //Serial.println("get! " + String(c, HEX)); - return c; -} - -void UPDI_io::init(void) -{ - HW_SERIAL.begin(230400, SERIAL_8E2); -} -#endif //UPDI_IO_TYPE == 3 diff --git a/source/updi_io_uart.cpp b/source/updi_io_uart.cpp new file mode 100644 index 0000000..ff0e9bb --- /dev/null +++ b/source/updi_io_uart.cpp @@ -0,0 +1,73 @@ +/* + * updi_io.cpp + * + * Created: 18-11-2017 10:36:54 + * Author: JMR_2 + */ + + + +// Includes +#include +#include "updi_io.h" +#include "sys.h" + + +#if UPDI_IO_TYPE == 3 +#include + +// Functions +/* Sends regular characters through the UPDI link */ +uint8_t UPDI_io::put(char c) { + HW_SERIAL.write(c); + HW_SERIAL.flush(); + //delayMicroseconds(10); + long start = millis(); + while (!HW_SERIAL.available() && millis() - start < 20) {} + char d = HW_SERIAL.read(); + if (c != d) { + // Serial.println("echo failed! " + String(d, HEX)); + } + return c; +} + +/* Sends special sequences through the UPDI link */ +uint8_t UPDI_io::put(ctrl c) +{ + HW_SERIAL.begin(300, SERIAL_8N1); + switch (c) { + case double_break: + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + break; + case single_break: + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + break; + default: + break; + } + delay(15); + while (HW_SERIAL.available()) { + HW_SERIAL.read(); + } + HW_SERIAL.begin(230400, SERIAL_8E2); + return 0; +} + +uint8_t UPDI_io::get() { + uint8_t c; + while (!HW_SERIAL.available()) {} + c = HW_SERIAL.read(); + //delayMicroseconds(5); + //Serial.println("get! " + String(c, HEX)); + return c; +} + +void UPDI_io::init(void) +{ + HW_SERIAL.begin(230400, SERIAL_8E2); +} +#endif //UPDI_IO_TYPE == 3 diff --git a/source/updi_io_uart.h b/source/updi_io_uart.h new file mode 100644 index 0000000..d72b85e --- /dev/null +++ b/source/updi_io_uart.h @@ -0,0 +1,25 @@ +/* + * updi_io.h + * + * Created: 18-11-2017 10:38:31 + * Author: JMR_2 + */ + + +#ifndef UPDI_IO_H_ +#define UPDI_IO_H_ + +#include + +namespace UPDI_io { + // Enums + enum ctrl {single_break, double_break, enable}; + + // Function prototypes + uint8_t put(char) __attribute__((optimize("no-tree-loop-optimize"))); + uint8_t put(ctrl); + uint8_t get() __attribute__((optimize("no-tree-loop-optimize"))); + void init(void); +} + +#endif /* UPDI_IO_H_ */ \ No newline at end of file From 226fd8e7887feb36085537eeafb6c63e3ea49596 Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 4 Feb 2020 08:46:20 +0100 Subject: [PATCH 04/14] Add files via upload Separated files for UPDI using bitbang/UART. Forgot to add changed Jtag2.cpp. --- JTAG2.cpp | 373 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 JTAG2.cpp diff --git a/JTAG2.cpp b/JTAG2.cpp new file mode 100644 index 0000000..76d2214 --- /dev/null +++ b/JTAG2.cpp @@ -0,0 +1,373 @@ +/* + * STK500.cpp + * + * Created: 08-12-2017 19:47:27 + * Author: JMR_2 + */ + +#include "JTAG2.h" +#include "JICE_io.h" +#include "NVM.h" +#include "crc16.h" +#include "UPDI_hi_lvl.h" + +// *** Writeable Parameter Values *** +uint8_t JTAG2::PARAM_EMU_MODE_VAL; +JTAG2::baud_rate JTAG2::PARAM_BAUD_RATE_VAL; + +// *** STK500 packet *** +JTAG2::packet_t JTAG2::packet; + +namespace { + // *** Private variables *** + uint8_t flash_pagesize; + uint8_t eeprom_pagesize; + + // *** Local functions declaration *** + void NVM_fuse_write (uint16_t address, uint8_t data); + void NVM_buffered_write(uint16_t address, uint16_t lenght, uint8_t buff_size, uint8_t write_type); +} + +// *** Packet functions *** + bool JTAG2::receive() { + while (JICE_io::get() != MESSAGE_START); + uint16_t crc = CRC::next(MESSAGE_START); + for (uint16_t i = 0; i < 6; i++) { + crc = CRC::next(packet.raw[i] = JICE_io::get(), crc); + } + if (packet.size_word[0] > sizeof(packet.body)) return false; + if (JICE_io::get() != TOKEN) return false; + crc = CRC::next(TOKEN, crc); + for (uint16_t i = 0; i < packet.size_word[0]; i++) { + crc = CRC::next(packet.body[i] = JICE_io::get(), crc); + } + if ((uint16_t)(JICE_io::get() | (JICE_io::get() << 8)) != crc) return false; + return true; + } + + void JTAG2::answer() { + uint16_t crc = CRC::next(JICE_io::put(MESSAGE_START)); + for (uint16_t i = 0; i < 6; i++) { + crc = CRC::next(JICE_io::put(packet.raw[i]), crc); + } + crc = CRC::next(JICE_io::put(TOKEN), crc); + for (uint16_t i = 0; i < packet.size_word[0]; i++) { + crc = CRC::next(JICE_io::put(packet.body[i]), crc); + } + JICE_io::put(crc); + JICE_io::put(crc >> 8); + } + + void JTAG2::delay_exec() { + // wait for transmission complete + JICE_io::flush(); + // set baud rate + JICE_io::set_baud(PARAM_BAUD_RATE_VAL); + } + +// *** Set status function *** + void JTAG2::set_status(uint8_t status_code){ + packet.size_word[0] = 1; + packet.body[0] = status_code; + } + +// *** General command functions *** + // *** Signature response message *** + FLASH JTAG2::sgn_resp[29] { 0x86, 1, + 1, PARAM_FW_VER_M_MIN_VAL, PARAM_FW_VER_M_MAJ_VAL, PARAM_HW_VER_M_VAL, + 1, PARAM_FW_VER_S_MIN_VAL, PARAM_FW_VER_S_MAJ_VAL, PARAM_HW_VER_S_VAL, + 0, 0, 0, 0, 0, 0, + 'J', 'T', 'A', 'G', 'I', 'C', 'E', ' ', 'm', 'k', 'I', 'I', 0}; + void JTAG2::sign_on(){ + // Initialize JTAGICE2 variables + JTAG2::PARAM_EMU_MODE_VAL = 0x02; + JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; + /* Initialize or enable UPDI */ + UPDI_io::put(UPDI_io::double_break); +#if UPDI_IO_TYPE == 3 + // Timing Type3 - UPDI UART + // Bit 3 - Collision and Contention Detection Disable + UPDI::stcs(UPDI::reg::Control_B, 8); + // Bit 7 – IBDLY Inter-Byte Delay Enable + // Bit 5=0 Parity enable + // Bit 4=0 Time-out detection enable + // Bit 3=0 RSD Response Signature Enable + // Bit 2:0 0x0 UPDI Guard Time: 128 cycles (default) + UPDI::stcs(UPDI::reg::Control_A, 0x80); +#else + // Timing Type1 UPDI bitbang + // UPDI Guard Time: 2 cycles + UPDI::stcs(UPDI::reg::Control_A, 6); +#endif + // Send sign on message + packet.size_word[0] = sizeof(sgn_resp); + for (uint8_t i = 0; i < sizeof(sgn_resp); i++) { + packet.body[i] = sgn_resp[i]; + } + } + + void JTAG2::get_parameter(){ + uint8_t & status = packet.body[0]; + uint8_t & parameter = packet.body[1]; + switch (parameter) { + case PARAM_HW_VER: + packet.size_word[0] = 3; + packet.body[1] = PARAM_HW_VER_M_VAL; + packet.body[2] = PARAM_HW_VER_S_VAL; + break; + case PARAM_FW_VER: + packet.size_word[0] = 5; + packet.body[1] = PARAM_FW_VER_M_MIN_VAL; + packet.body[2] = PARAM_FW_VER_M_MAJ_VAL; + packet.body[3] = PARAM_FW_VER_S_MIN_VAL; + packet.body[4] = PARAM_FW_VER_S_MAJ_VAL; + break; + case PARAM_EMU_MODE: + packet.size_word[0] = 2; + packet.body[1] = PARAM_EMU_MODE_VAL; + break; + case PARAM_BAUD_RATE: + packet.size_word[0] = 2; + packet.body[1] = PARAM_BAUD_RATE_VAL; + break; + case PARAM_VTARGET: + packet.size_word[0] = 3; + packet.body[1] = PARAM_VTARGET_VAL & 0xFF; + packet.body[2] = PARAM_VTARGET_VAL >> 8; + break; + default: + set_status(RSP_ILLEGAL_PARAMETER); + return; + } + status = RSP_PARAMETER; + return; + } + + void JTAG2::set_parameter(){ + uint8_t & parameter = packet.body[1]; + switch (parameter) { + case PARAM_EMU_MODE: + PARAM_EMU_MODE_VAL = packet.body[2]; + break; + case PARAM_BAUD_RATE: + PARAM_BAUD_RATE_VAL = (baud_rate)packet.body[2]; + break; + default: + set_status(RSP_ILLEGAL_PARAMETER); + return; + } + set_status(RSP_OK); + } + + void JTAG2::set_device_descriptor(){ + flash_pagesize = packet.body[244]; + eeprom_pagesize = packet.body[246]; + set_status(RSP_OK); + } + +// *** Target mode set functions *** + // *** Sets MCU in program mode, if possibe *** + void JTAG2::enter_progmode(){ + // Reset the MCU now, to prevent the WDT (if active) to reset it at an unpredictable moment + UPDI::CPU_reset(); + // Now we have time to enter program mode (this mode also disables the WDT) + const uint8_t system_status = UPDI::CPU_mode<0xEF>(); + switch (system_status){ + // in normal operation mode + case 0x82: + // Write NVN unlock key (allows read access to all addressing space) + UPDI::write_key(UPDI::NVM_Prog); + // Request reset + UPDI::CPU_reset(); + // Wait for NVM unlock state + //while (UPDI::CPU_mode() != 0x08); + // already in program mode + case 0x08: + // better clear the page buffer, just in case. + UPDI::sts_b(NVM::NVM_base | NVM::CTRLA, NVM::PBC); + // Turn on LED to indicate program mode + SYS::setLED(); + set_status(RSP_OK); + break; + // in other modes fail and inform host of wrong mode + default: + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = system_status; // 0x01; + } + } + + // *** Sets MCU in normal runnning mode, if possibe *** + void JTAG2::leave_progmode(){ + const uint8_t system_status = UPDI::CPU_mode<0xEF>(); + switch (system_status){ + // in program mode + case 0x08: + // Request reset + UPDI::CPU_reset(); + // Wait for normal mode + // while (UPDI::CPU_mode<0xEF>() != 0x82); + // already in normal mode + case 0x82: + // Turn off LED to indicate normal mode + SYS::clearLED(); + set_status(RSP_OK); + break; + // in other modes fail and inform host of wrong mode + default: + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = system_status; // 0x01; + } + } + +// *** Read/Write/Erase functions *** + + void JTAG2::read_mem() { + if (UPDI::CPU_mode() != 0x08){ + // fail if not in program mode + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = 0x01; + } + else { + // in program mode + const uint16_t NumBytes = (packet.body[3] << 8) | packet.body[2]; + // Get physical address for reading + const uint16_t address = (packet.body[7] << 8) | packet.body[6]; + // Set UPDI pointer to address + UPDI::stptr_w(address); + // Read block + UPDI::rep(NumBytes - 1); + packet.body[1] = UPDI::ldinc_b(); + for (uint16_t i = 2; i <= NumBytes; i++) { + packet.body[i] = UPDI_io::get(); + } + packet.size_word[0] = NumBytes + 1; + packet.body[0] = RSP_MEMORY; + } + } + + void JTAG2::write_mem() { + if (UPDI::CPU_mode() != 0x08){ + // fail if not in program mode + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = 0x01; + } + else { + // in program mode + const uint8_t mem_type = packet.body[1]; + const uint16_t address = packet.body[6] | (packet.body[7] << 8); + const uint16_t lenght = packet.body[2] | (packet.body[3] << 8); /* number of bytes to write */ + const bool is_flash = ((mem_type == MTYPE_FLASH) || (mem_type == MTYPE_BOOT_FLASH)); + const uint8_t buff_size = is_flash ? flash_pagesize : eeprom_pagesize; + const uint8_t write_cmnd = is_flash ? NVM::WP : NVM::ERWP; + switch (mem_type) { + case MTYPE_FUSE_BITS: + case MTYPE_LOCK_BITS: + NVM_fuse_write (address, packet.body[10]); + break; + case MTYPE_FLASH: + case MTYPE_BOOT_FLASH: + case MTYPE_EEPROM_XMEGA: + case MTYPE_USERSIG: + NVM_buffered_write(address, lenght, buff_size, write_cmnd); + break; + default: + set_status(RSP_ILLEGAL_MEMORY_TYPE); + return; + } + set_status(RSP_OK); + } + } + + void JTAG2::erase() { + const uint8_t erase_type = packet.body[1]; + const uint16_t address = packet.body[2] | (packet.body[3] << 8); + switch (erase_type) { + case 0: + // Write Chip Erase key + UPDI::write_key(UPDI::Chip_Erase); + // Request reset + UPDI::CPU_reset(); + // Erase chip process exits program mode, reenter... + enter_progmode(); + break; + case 4: + case 5: + NVM::wait(); + UPDI::sts_b(address, 0xFF); + NVM::command(NVM::ER); + set_status(RSP_OK); + break; + case 6: + case 7: + break; + default: + set_status(RSP_FAILED); + } + } + +// *** Local functions definition *** +namespace { + void NVM_fuse_write (uint16_t address, uint8_t data) { + // Setup UPDI pointer + UPDI::stptr_w(NVM::NVM_base + NVM::DATA_lo); + // Send data to the NVM controller + UPDI::stinc_b(data); + UPDI::stinc_b(0x00); + // Send address to the NVM controller + UPDI::stinc_b(address & 0xFF); + UPDI::stinc_b(address >> 8); + // Execute fuse write + NVM::command(NVM::WFU); + } + + void NVM_buffered_write(const uint16_t address, const uint16_t length, const uint8_t buff_size, const uint8_t write_cmnd) { + uint8_t current_byte_index = 10; /* Index of the first byte to send inside the JTAG2 command body */ + uint16_t bytes_remaining = length; /* number of bytes to write */ + + // Sends a block of bytes from the command body to memory, using the UPDI interface + // On entry, the UPDI pointer must already point to the desired address + // On exit, the UPDI pointer points to the next byte after the last one written + // Returns updated index into the command body, pointing to the first unsent byte. + auto updi_send_block = [] (uint8_t count, uint8_t index) { + count--; + NVM::wait(); + UPDI::rep(count); + UPDI::stinc_b(JTAG2::packet.body[index]); + for (uint8_t i = count; i; i--) { + UPDI_io::put(JTAG2::packet.body[++index]); + UPDI_io::get(); + } + return ++index; + }; + + // Setup UPDI pointer for block transfer + UPDI::stptr_w(address); + /* Check address alignment, calculate number of unaligned bytes to send */ + uint8_t unaligned_bytes = (-address & (buff_size - 1)); + if (unaligned_bytes > bytes_remaining) unaligned_bytes = bytes_remaining; + /* If there are unaligned bytes, they must be sent first */ + if (unaligned_bytes) { + // Send unaligned block + current_byte_index = updi_send_block(unaligned_bytes, current_byte_index); + bytes_remaining -= unaligned_bytes; + NVM::command(write_cmnd); + } + while (bytes_remaining) { + /* Send a buff_size amount of bytes */ + if (bytes_remaining >= buff_size) { + current_byte_index = updi_send_block(buff_size, current_byte_index); + bytes_remaining -= buff_size; + } + /* Send a NumBytes amount of bytes */ + else { + current_byte_index = updi_send_block(bytes_remaining, current_byte_index); + bytes_remaining = 0; + } + NVM::command(write_cmnd); + } + } +} From f88640e7560fb2099872f1193a45e998fb3bff0f Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Mon, 17 Feb 2020 20:10:51 +0100 Subject: [PATCH 05/14] added support for 32U4 32U4 support only working using Linux right now due to a bug in windows not allowing the 32U4 to send a reply to avrdude. --- JICE_io.cpp | 119 ++++++++ JTAG2.cpp | 749 ++++++++++++++++++++++++----------------------- jtag2updi.cpp | 121 ++++++++ sys.cpp | 105 +++++++ sys.h | 207 +++++++++++++ updi_io.cpp | 224 ++++++++++++++ updi_io_uart.cpp | 73 +++++ updi_io_uart.h | 25 ++ 8 files changed, 1250 insertions(+), 373 deletions(-) create mode 100644 JICE_io.cpp create mode 100644 jtag2updi.cpp create mode 100644 sys.cpp create mode 100644 sys.h create mode 100644 updi_io.cpp create mode 100644 updi_io_uart.cpp create mode 100644 updi_io_uart.h diff --git a/JICE_io.cpp b/JICE_io.cpp new file mode 100644 index 0000000..76f709d --- /dev/null +++ b/JICE_io.cpp @@ -0,0 +1,119 @@ +/* + * stk_io.cpp + * + * Created: 18-11-2017 15:20:29 + * Author: JMR_2 + */ + +// Includes +#include +#include +#include "JICE_io.h" +#include "sys.h" + +namespace { + // *** Baud rate lookup table for UBRR0 register *** + // Indexed by valid values for PARAM_BAUD_RATE_VAL (defined in JTAG2.h) + FLASH baud_tbl[8] = {baud_reg_val(2400), baud_reg_val(4800), baud_reg_val(9600), baud_reg_val(19200), baud_reg_val(38400), baud_reg_val(57600), baud_reg_val(115200), baud_reg_val(14400)}; +} + +// Functions +uint8_t JICE_io::put(char c) { +#ifdef __AVR_ATmega16__ + loop_until_bit_is_set(UCSRA, UDRE); + return UDR = c; +#elif defined XTINY + loop_until_bit_is_set(HOST_USART.STATUS, USART_DREIF_bp); + return HOST_USART.TXDATAL = c; +#elif defined __AVR_ATmega32U4__ + // wait for Serial to be active + // while (!SERIALCOM); + // commented out: timeout/error communicating with programmer (status -1) + SERIALCOM.write(c); + return c; +#else + loop_until_bit_is_set(UCSR0A, UDRE0); + return UDR0 = c; +#endif +} + +uint8_t JICE_io::get(void) { +#ifdef __AVR_ATmega16__ + loop_until_bit_is_set(UCSRA, RXC); /* Wait until data exists. */ + return UDR; +#elif defined XTINY + loop_until_bit_is_set(HOST_USART.STATUS, USART_RXCIF_bp); /* Wait until data exists. */ + return HOST_USART.RXDATAL; +#elif defined __AVR_ATmega32U4__ + uint8_t c = SERIALCOM.read(); + return c; +#else + loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ + return UDR0; +#endif +} + +void JICE_io::init(void) { +#ifdef __AVR_ATmega16__ + /* Set double speed */ + UCSRA = (1< sizeof(packet.body)) return false; - if (JICE_io::get() != TOKEN) return false; - crc = CRC::next(TOKEN, crc); - for (uint16_t i = 0; i < packet.size_word[0]; i++) { - crc = CRC::next(packet.body[i] = JICE_io::get(), crc); - } - if ((uint16_t)(JICE_io::get() | (JICE_io::get() << 8)) != crc) return false; - return true; - } - - void JTAG2::answer() { - uint16_t crc = CRC::next(JICE_io::put(MESSAGE_START)); - for (uint16_t i = 0; i < 6; i++) { - crc = CRC::next(JICE_io::put(packet.raw[i]), crc); - } - crc = CRC::next(JICE_io::put(TOKEN), crc); - for (uint16_t i = 0; i < packet.size_word[0]; i++) { - crc = CRC::next(JICE_io::put(packet.body[i]), crc); - } - JICE_io::put(crc); - JICE_io::put(crc >> 8); - } - - void JTAG2::delay_exec() { - // wait for transmission complete - JICE_io::flush(); - // set baud rate - JICE_io::set_baud(PARAM_BAUD_RATE_VAL); - } - -// *** Set status function *** - void JTAG2::set_status(uint8_t status_code){ - packet.size_word[0] = 1; - packet.body[0] = status_code; - } - -// *** General command functions *** - // *** Signature response message *** - FLASH JTAG2::sgn_resp[29] { 0x86, 1, - 1, PARAM_FW_VER_M_MIN_VAL, PARAM_FW_VER_M_MAJ_VAL, PARAM_HW_VER_M_VAL, - 1, PARAM_FW_VER_S_MIN_VAL, PARAM_FW_VER_S_MAJ_VAL, PARAM_HW_VER_S_VAL, - 0, 0, 0, 0, 0, 0, - 'J', 'T', 'A', 'G', 'I', 'C', 'E', ' ', 'm', 'k', 'I', 'I', 0}; - void JTAG2::sign_on(){ - // Initialize JTAGICE2 variables - JTAG2::PARAM_EMU_MODE_VAL = 0x02; - JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; - /* Initialize or enable UPDI */ - UPDI_io::put(UPDI_io::double_break); -#if UPDI_IO_TYPE == 3 - // Timing Type3 - UPDI UART - // Bit 3 - Collision and Contention Detection Disable - UPDI::stcs(UPDI::reg::Control_B, 8); - // Bit 7 – IBDLY Inter-Byte Delay Enable - // Bit 5=0 Parity enable - // Bit 4=0 Time-out detection enable - // Bit 3=0 RSD Response Signature Enable - // Bit 2:0 0x0 UPDI Guard Time: 128 cycles (default) - UPDI::stcs(UPDI::reg::Control_A, 0x80); -#else - // Timing Type1 UPDI bitbang - // UPDI Guard Time: 2 cycles - UPDI::stcs(UPDI::reg::Control_A, 6); -#endif - // Send sign on message - packet.size_word[0] = sizeof(sgn_resp); - for (uint8_t i = 0; i < sizeof(sgn_resp); i++) { - packet.body[i] = sgn_resp[i]; - } - } - - void JTAG2::get_parameter(){ - uint8_t & status = packet.body[0]; - uint8_t & parameter = packet.body[1]; - switch (parameter) { - case PARAM_HW_VER: - packet.size_word[0] = 3; - packet.body[1] = PARAM_HW_VER_M_VAL; - packet.body[2] = PARAM_HW_VER_S_VAL; - break; - case PARAM_FW_VER: - packet.size_word[0] = 5; - packet.body[1] = PARAM_FW_VER_M_MIN_VAL; - packet.body[2] = PARAM_FW_VER_M_MAJ_VAL; - packet.body[3] = PARAM_FW_VER_S_MIN_VAL; - packet.body[4] = PARAM_FW_VER_S_MAJ_VAL; - break; - case PARAM_EMU_MODE: - packet.size_word[0] = 2; - packet.body[1] = PARAM_EMU_MODE_VAL; - break; - case PARAM_BAUD_RATE: - packet.size_word[0] = 2; - packet.body[1] = PARAM_BAUD_RATE_VAL; - break; - case PARAM_VTARGET: - packet.size_word[0] = 3; - packet.body[1] = PARAM_VTARGET_VAL & 0xFF; - packet.body[2] = PARAM_VTARGET_VAL >> 8; - break; - default: - set_status(RSP_ILLEGAL_PARAMETER); - return; - } - status = RSP_PARAMETER; - return; - } - - void JTAG2::set_parameter(){ - uint8_t & parameter = packet.body[1]; - switch (parameter) { - case PARAM_EMU_MODE: - PARAM_EMU_MODE_VAL = packet.body[2]; - break; - case PARAM_BAUD_RATE: - PARAM_BAUD_RATE_VAL = (baud_rate)packet.body[2]; - break; - default: - set_status(RSP_ILLEGAL_PARAMETER); - return; - } - set_status(RSP_OK); - } - - void JTAG2::set_device_descriptor(){ - flash_pagesize = packet.body[244]; - eeprom_pagesize = packet.body[246]; - set_status(RSP_OK); - } - -// *** Target mode set functions *** - // *** Sets MCU in program mode, if possibe *** - void JTAG2::enter_progmode(){ - // Reset the MCU now, to prevent the WDT (if active) to reset it at an unpredictable moment - UPDI::CPU_reset(); - // Now we have time to enter program mode (this mode also disables the WDT) - const uint8_t system_status = UPDI::CPU_mode<0xEF>(); - switch (system_status){ - // in normal operation mode - case 0x82: - // Write NVN unlock key (allows read access to all addressing space) - UPDI::write_key(UPDI::NVM_Prog); - // Request reset - UPDI::CPU_reset(); - // Wait for NVM unlock state - //while (UPDI::CPU_mode() != 0x08); - // already in program mode - case 0x08: - // better clear the page buffer, just in case. - UPDI::sts_b(NVM::NVM_base | NVM::CTRLA, NVM::PBC); - // Turn on LED to indicate program mode - SYS::setLED(); - set_status(RSP_OK); - break; - // in other modes fail and inform host of wrong mode - default: - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = system_status; // 0x01; - } - } - - // *** Sets MCU in normal runnning mode, if possibe *** - void JTAG2::leave_progmode(){ - const uint8_t system_status = UPDI::CPU_mode<0xEF>(); - switch (system_status){ - // in program mode - case 0x08: - // Request reset - UPDI::CPU_reset(); - // Wait for normal mode - // while (UPDI::CPU_mode<0xEF>() != 0x82); - // already in normal mode - case 0x82: - // Turn off LED to indicate normal mode - SYS::clearLED(); - set_status(RSP_OK); - break; - // in other modes fail and inform host of wrong mode - default: - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = system_status; // 0x01; - } - } - -// *** Read/Write/Erase functions *** - - void JTAG2::read_mem() { - if (UPDI::CPU_mode() != 0x08){ - // fail if not in program mode - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = 0x01; - } - else { - // in program mode - const uint16_t NumBytes = (packet.body[3] << 8) | packet.body[2]; - // Get physical address for reading - const uint16_t address = (packet.body[7] << 8) | packet.body[6]; - // Set UPDI pointer to address - UPDI::stptr_w(address); - // Read block - UPDI::rep(NumBytes - 1); - packet.body[1] = UPDI::ldinc_b(); - for (uint16_t i = 2; i <= NumBytes; i++) { - packet.body[i] = UPDI_io::get(); - } - packet.size_word[0] = NumBytes + 1; - packet.body[0] = RSP_MEMORY; - } - } - - void JTAG2::write_mem() { - if (UPDI::CPU_mode() != 0x08){ - // fail if not in program mode - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = 0x01; - } - else { - // in program mode - const uint8_t mem_type = packet.body[1]; - const uint16_t address = packet.body[6] | (packet.body[7] << 8); - const uint16_t lenght = packet.body[2] | (packet.body[3] << 8); /* number of bytes to write */ - const bool is_flash = ((mem_type == MTYPE_FLASH) || (mem_type == MTYPE_BOOT_FLASH)); - const uint8_t buff_size = is_flash ? flash_pagesize : eeprom_pagesize; - const uint8_t write_cmnd = is_flash ? NVM::WP : NVM::ERWP; - switch (mem_type) { - case MTYPE_FUSE_BITS: - case MTYPE_LOCK_BITS: - NVM_fuse_write (address, packet.body[10]); - break; - case MTYPE_FLASH: - case MTYPE_BOOT_FLASH: - case MTYPE_EEPROM_XMEGA: - case MTYPE_USERSIG: - NVM_buffered_write(address, lenght, buff_size, write_cmnd); - break; - default: - set_status(RSP_ILLEGAL_MEMORY_TYPE); - return; - } - set_status(RSP_OK); - } - } - - void JTAG2::erase() { - const uint8_t erase_type = packet.body[1]; - const uint16_t address = packet.body[2] | (packet.body[3] << 8); - switch (erase_type) { - case 0: - // Write Chip Erase key - UPDI::write_key(UPDI::Chip_Erase); - // Request reset - UPDI::CPU_reset(); - // Erase chip process exits program mode, reenter... - enter_progmode(); - break; - case 4: - case 5: - NVM::wait(); - UPDI::sts_b(address, 0xFF); - NVM::command(NVM::ER); - set_status(RSP_OK); - break; - case 6: - case 7: - break; - default: - set_status(RSP_FAILED); - } - } - -// *** Local functions definition *** -namespace { - void NVM_fuse_write (uint16_t address, uint8_t data) { - // Setup UPDI pointer - UPDI::stptr_w(NVM::NVM_base + NVM::DATA_lo); - // Send data to the NVM controller - UPDI::stinc_b(data); - UPDI::stinc_b(0x00); - // Send address to the NVM controller - UPDI::stinc_b(address & 0xFF); - UPDI::stinc_b(address >> 8); - // Execute fuse write - NVM::command(NVM::WFU); - } - - void NVM_buffered_write(const uint16_t address, const uint16_t length, const uint8_t buff_size, const uint8_t write_cmnd) { - uint8_t current_byte_index = 10; /* Index of the first byte to send inside the JTAG2 command body */ - uint16_t bytes_remaining = length; /* number of bytes to write */ - - // Sends a block of bytes from the command body to memory, using the UPDI interface - // On entry, the UPDI pointer must already point to the desired address - // On exit, the UPDI pointer points to the next byte after the last one written - // Returns updated index into the command body, pointing to the first unsent byte. - auto updi_send_block = [] (uint8_t count, uint8_t index) { - count--; - NVM::wait(); - UPDI::rep(count); - UPDI::stinc_b(JTAG2::packet.body[index]); - for (uint8_t i = count; i; i--) { - UPDI_io::put(JTAG2::packet.body[++index]); - UPDI_io::get(); - } - return ++index; - }; - - // Setup UPDI pointer for block transfer - UPDI::stptr_w(address); - /* Check address alignment, calculate number of unaligned bytes to send */ - uint8_t unaligned_bytes = (-address & (buff_size - 1)); - if (unaligned_bytes > bytes_remaining) unaligned_bytes = bytes_remaining; - /* If there are unaligned bytes, they must be sent first */ - if (unaligned_bytes) { - // Send unaligned block - current_byte_index = updi_send_block(unaligned_bytes, current_byte_index); - bytes_remaining -= unaligned_bytes; - NVM::command(write_cmnd); - } - while (bytes_remaining) { - /* Send a buff_size amount of bytes */ - if (bytes_remaining >= buff_size) { - current_byte_index = updi_send_block(buff_size, current_byte_index); - bytes_remaining -= buff_size; - } - /* Send a NumBytes amount of bytes */ - else { - current_byte_index = updi_send_block(bytes_remaining, current_byte_index); - bytes_remaining = 0; - } - NVM::command(write_cmnd); - } - } -} +/* + * STK500.cpp + * + * Created: 08-12-2017 19:47:27 + * Author: JMR_2 + */ + +#include "JTAG2.h" +#include "JICE_io.h" +#include "NVM.h" +#include "crc16.h" +#include "UPDI_hi_lvl.h" + +// *** Writeable Parameter Values *** +uint8_t JTAG2::PARAM_EMU_MODE_VAL; +JTAG2::baud_rate JTAG2::PARAM_BAUD_RATE_VAL; + +// *** STK500 packet *** +JTAG2::packet_t JTAG2::packet; + +namespace { + // *** Private variables *** + uint8_t flash_pagesize; + uint8_t eeprom_pagesize; + + // *** Local functions declaration *** + void NVM_fuse_write (uint16_t address, uint8_t data); + void NVM_buffered_write(uint16_t address, uint16_t lenght, uint8_t buff_size, uint8_t write_type); +} + +// *** Packet functions *** + bool JTAG2::receive() { + while (JICE_io::get() != MESSAGE_START); + uint16_t crc = CRC::next(MESSAGE_START); + for (uint16_t i = 0; i < 6; i++) { + crc = CRC::next(packet.raw[i] = JICE_io::get(), crc); + } + if (packet.size_word[0] > sizeof(packet.body)) return false; + if (JICE_io::get() != TOKEN) return false; + crc = CRC::next(TOKEN, crc); + for (uint16_t i = 0; i < packet.size_word[0]; i++) { + crc = CRC::next(packet.body[i] = JICE_io::get(), crc); + } + if ((uint16_t)(JICE_io::get() | (JICE_io::get() << 8)) != crc) return false; + return true; + } + + void JTAG2::answer() { + uint16_t crc = CRC::next(JICE_io::put(MESSAGE_START)); + for (uint16_t i = 0; i < 6; i++) { + crc = CRC::next(JICE_io::put(packet.raw[i]), crc); + } + crc = CRC::next(JICE_io::put(TOKEN), crc); + for (uint16_t i = 0; i < packet.size_word[0]; i++) { + crc = CRC::next(JICE_io::put(packet.body[i]), crc); + } + JICE_io::put(crc); + JICE_io::put(crc >> 8); + } + + void JTAG2::delay_exec() { + // wait for transmission complete + JICE_io::flush(); + // set baud rate + JICE_io::set_baud(PARAM_BAUD_RATE_VAL); + } + +// *** Set status function *** + void JTAG2::set_status(uint8_t status_code){ + packet.size_word[0] = 1; + packet.body[0] = status_code; + } + +// *** General command functions *** + // *** Signature response message *** + FLASH JTAG2::sgn_resp[29] { 0x86, 1, + 1, PARAM_FW_VER_M_MIN_VAL, PARAM_FW_VER_M_MAJ_VAL, PARAM_HW_VER_M_VAL, + 1, PARAM_FW_VER_S_MIN_VAL, PARAM_FW_VER_S_MAJ_VAL, PARAM_HW_VER_S_VAL, + 0, 0, 0, 0, 0, 0, + 'J', 'T', 'A', 'G', 'I', 'C', 'E', ' ', 'm', 'k', 'I', 'I', 0}; + void JTAG2::sign_on(){ + // Initialize JTAGICE2 variables + JTAG2::PARAM_EMU_MODE_VAL = 0x02; + JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; + /* Initialize or enable UPDI */ + UPDI_io::put(UPDI_io::double_break); +#if UPDI_IO_TYPE == 3 + // use timing from MEGA_AVR project, but worked with timing from bitbang as well + + // Timing Type3 - UPDI UART + // Bit 3 - Collision and Contention Detection Disable + UPDI::stcs(UPDI::reg::Control_B, 8); + // Bit 7 – IBDLY Inter-Byte Delay Enable + // Bit 5=0 Parity enable + // Bit 4=0 Time-out detection enable + // Bit 3=0 RSD Response Signature Enable + // Bit 2:0 0x0 UPDI Guard Time: 128 cycles (default) + UPDI::stcs(UPDI::reg::Control_A, 0x80); + //UPDI::stcs(UPDI::reg::Control_A, 6); +#else + // Timing Type1 UPDI bitbang + // UPDI Guard Time: 2 cycles + UPDI::stcs(UPDI::reg::Control_A, 6); +#endif + // Send sign on message + packet.size_word[0] = sizeof(sgn_resp); + for (uint8_t i = 0; i < sizeof(sgn_resp); i++) { + packet.body[i] = sgn_resp[i]; + } + } + + void JTAG2::get_parameter(){ + uint8_t & status = packet.body[0]; + uint8_t & parameter = packet.body[1]; + switch (parameter) { + case PARAM_HW_VER: + packet.size_word[0] = 3; + packet.body[1] = PARAM_HW_VER_M_VAL; + packet.body[2] = PARAM_HW_VER_S_VAL; + break; + case PARAM_FW_VER: + packet.size_word[0] = 5; + packet.body[1] = PARAM_FW_VER_M_MIN_VAL; + packet.body[2] = PARAM_FW_VER_M_MAJ_VAL; + packet.body[3] = PARAM_FW_VER_S_MIN_VAL; + packet.body[4] = PARAM_FW_VER_S_MAJ_VAL; + break; + case PARAM_EMU_MODE: + packet.size_word[0] = 2; + packet.body[1] = PARAM_EMU_MODE_VAL; + break; + case PARAM_BAUD_RATE: + packet.size_word[0] = 2; + packet.body[1] = PARAM_BAUD_RATE_VAL; + break; + case PARAM_VTARGET: + packet.size_word[0] = 3; + packet.body[1] = PARAM_VTARGET_VAL & 0xFF; + packet.body[2] = PARAM_VTARGET_VAL >> 8; + break; + default: + set_status(RSP_ILLEGAL_PARAMETER); + return; + } + status = RSP_PARAMETER; + return; + } + + void JTAG2::set_parameter(){ + uint8_t & parameter = packet.body[1]; + switch (parameter) { + case PARAM_EMU_MODE: + PARAM_EMU_MODE_VAL = packet.body[2]; + break; + case PARAM_BAUD_RATE: + PARAM_BAUD_RATE_VAL = (baud_rate)packet.body[2]; + break; + default: + set_status(RSP_ILLEGAL_PARAMETER); + return; + } + set_status(RSP_OK); + } + + void JTAG2::set_device_descriptor(){ + flash_pagesize = packet.body[244]; + eeprom_pagesize = packet.body[246]; + set_status(RSP_OK); + } + +// *** Target mode set functions *** + // *** Sets MCU in program mode, if possibe *** + void JTAG2::enter_progmode(){ + // Reset the MCU now, to prevent the WDT (if active) to reset it at an unpredictable moment + UPDI::CPU_reset(); + // Now we have time to enter program mode (this mode also disables the WDT) + const uint8_t system_status = UPDI::CPU_mode<0xEF>(); + switch (system_status){ + // in normal operation mode + case 0x82: + // Write NVN unlock key (allows read access to all addressing space) + UPDI::write_key(UPDI::NVM_Prog); + // Request reset + UPDI::CPU_reset(); + // Wait for NVM unlock state + //while (UPDI::CPU_mode() != 0x08); + // already in program mode + case 0x08: + // better clear the page buffer, just in case. + UPDI::sts_b(NVM::NVM_base | NVM::CTRLA, NVM::PBC); + // Turn on LED to indicate program mode + SYS::setLED(); + set_status(RSP_OK); + break; + // in other modes fail and inform host of wrong mode + default: + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = system_status; // 0x01; + } + } + + // *** Sets MCU in normal runnning mode, if possibe *** + void JTAG2::leave_progmode(){ + const uint8_t system_status = UPDI::CPU_mode<0xEF>(); + switch (system_status){ + // in program mode + case 0x08: + // Request reset + UPDI::CPU_reset(); + // Wait for normal mode + // while (UPDI::CPU_mode<0xEF>() != 0x82); + // already in normal mode + case 0x82: + // Turn off LED to indicate normal mode + SYS::clearLED(); + set_status(RSP_OK); + break; + // in other modes fail and inform host of wrong mode + default: + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = system_status; // 0x01; + } + } + +// *** Read/Write/Erase functions *** + + void JTAG2::read_mem() { + if (UPDI::CPU_mode() != 0x08){ + // fail if not in program mode + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = 0x01; + } + else { + // in program mode + const uint16_t NumBytes = (packet.body[3] << 8) | packet.body[2]; + // Get physical address for reading + const uint16_t address = (packet.body[7] << 8) | packet.body[6]; + // Set UPDI pointer to address + UPDI::stptr_w(address); + // Read block + UPDI::rep(NumBytes - 1); + packet.body[1] = UPDI::ldinc_b(); + for (uint16_t i = 2; i <= NumBytes; i++) { + packet.body[i] = UPDI_io::get(); + } + packet.size_word[0] = NumBytes + 1; + packet.body[0] = RSP_MEMORY; + } + } + + void JTAG2::write_mem() { + if (UPDI::CPU_mode() != 0x08){ + // fail if not in program mode + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = 0x01; + } + else { + // in program mode + const uint8_t mem_type = packet.body[1]; + const uint16_t address = packet.body[6] | (packet.body[7] << 8); + const uint16_t lenght = packet.body[2] | (packet.body[3] << 8); /* number of bytes to write */ + const bool is_flash = ((mem_type == MTYPE_FLASH) || (mem_type == MTYPE_BOOT_FLASH)); + const uint8_t buff_size = is_flash ? flash_pagesize : eeprom_pagesize; + const uint8_t write_cmnd = is_flash ? NVM::WP : NVM::ERWP; + switch (mem_type) { + case MTYPE_FUSE_BITS: + case MTYPE_LOCK_BITS: + NVM_fuse_write (address, packet.body[10]); + break; + case MTYPE_FLASH: + case MTYPE_BOOT_FLASH: + case MTYPE_EEPROM_XMEGA: + case MTYPE_USERSIG: + NVM_buffered_write(address, lenght, buff_size, write_cmnd); + break; + default: + set_status(RSP_ILLEGAL_MEMORY_TYPE); + return; + } + set_status(RSP_OK); + } + } + + void JTAG2::erase() { + const uint8_t erase_type = packet.body[1]; + const uint16_t address = packet.body[2] | (packet.body[3] << 8); + switch (erase_type) { + case 0: + // Write Chip Erase key + UPDI::write_key(UPDI::Chip_Erase); + // Request reset + UPDI::CPU_reset(); + // Erase chip process exits program mode, reenter... + enter_progmode(); + break; + case 4: + case 5: + NVM::wait(); + UPDI::sts_b(address, 0xFF); + NVM::command(NVM::ER); + set_status(RSP_OK); + break; + case 6: + case 7: + break; + default: + set_status(RSP_FAILED); + } + } + +// *** Local functions definition *** +namespace { + void NVM_fuse_write (uint16_t address, uint8_t data) { + // Setup UPDI pointer + UPDI::stptr_w(NVM::NVM_base + NVM::DATA_lo); + // Send data to the NVM controller + UPDI::stinc_b(data); + UPDI::stinc_b(0x00); + // Send address to the NVM controller + UPDI::stinc_b(address & 0xFF); + UPDI::stinc_b(address >> 8); + // Execute fuse write + NVM::command(NVM::WFU); + } + + void NVM_buffered_write(const uint16_t address, const uint16_t length, const uint8_t buff_size, const uint8_t write_cmnd) { + uint8_t current_byte_index = 10; /* Index of the first byte to send inside the JTAG2 command body */ + uint16_t bytes_remaining = length; /* number of bytes to write */ + + // Sends a block of bytes from the command body to memory, using the UPDI interface + // On entry, the UPDI pointer must already point to the desired address + // On exit, the UPDI pointer points to the next byte after the last one written + // Returns updated index into the command body, pointing to the first unsent byte. + auto updi_send_block = [] (uint8_t count, uint8_t index) { + count--; + NVM::wait(); + UPDI::rep(count); + UPDI::stinc_b(JTAG2::packet.body[index]); + for (uint8_t i = count; i; i--) { + UPDI_io::put(JTAG2::packet.body[++index]); + UPDI_io::get(); + } + return ++index; + }; + + // Setup UPDI pointer for block transfer + UPDI::stptr_w(address); + /* Check address alignment, calculate number of unaligned bytes to send */ + uint8_t unaligned_bytes = (-address & (buff_size - 1)); + if (unaligned_bytes > bytes_remaining) unaligned_bytes = bytes_remaining; + /* If there are unaligned bytes, they must be sent first */ + if (unaligned_bytes) { + // Send unaligned block + current_byte_index = updi_send_block(unaligned_bytes, current_byte_index); + bytes_remaining -= unaligned_bytes; + NVM::command(write_cmnd); + } + while (bytes_remaining) { + /* Send a buff_size amount of bytes */ + if (bytes_remaining >= buff_size) { + current_byte_index = updi_send_block(buff_size, current_byte_index); + bytes_remaining -= buff_size; + } + /* Send a NumBytes amount of bytes */ + else { + current_byte_index = updi_send_block(bytes_remaining, current_byte_index); + bytes_remaining = 0; + } + NVM::command(write_cmnd); + } + } +} diff --git a/jtag2updi.cpp b/jtag2updi.cpp new file mode 100644 index 0000000..4caea0a --- /dev/null +++ b/jtag2updi.cpp @@ -0,0 +1,121 @@ +/* + * j2updi.cpp + * + * Created: 11-11-2017 22:29:58 + * Author : JMR_2 + */ + +// Includes +#if defined __AVR_ATmega32U4__ + #include + #include "USBAPI.h" + +// Declared weak in Arduino.h to allow user redefinitions. + int atexit(void (* /*func*/ )()) { return 0; } + +// Weak empty variant initialization function. +// May be redefined by variant files. + void initVariant() __attribute__((weak)); + void initVariant() { } + + void setupUSB() __attribute__((weak)); + void setupUSB() { } + +#endif + +#include "sys.h" +#if UPDI_IO_TYPE==3 + #include "updi_io_uart.h" +#else + #include "updi_io.h" +#endif +#include "JICE_io.h" +#include "JTAG2.h" + +/* Internal stuff */ +namespace { + // Prototypes + void setup2(); + void loop2(); +} + +int main(void) +{ + #if defined __AVR_ATmega32U4__ + init(); + initVariant(); + #endif + + #if defined(USBCON) + USBDevice.attach(); + #endif + setup2(); + loop2(); +} + +/* Internal stuff */ +namespace { + inline void setup2() { + /* Initialize MCU */ + SYS::init(); + + /* Initialize serial links */ + JICE_io::init(); + UPDI_io::init(); + } + + + inline void loop2() { + while (1) { + + // Receive command + while(!JTAG2::receive()); + // Process command + switch (JTAG2::packet.body[0]) { + case JTAG2::CMND_GET_SIGN_ON: + JTAG2::sign_on(); + break; + case JTAG2::CMND_GET_PARAMETER: + JTAG2::get_parameter(); + break; + case JTAG2::CMND_SET_PARAMETER: + JTAG2::set_parameter(); + break; + case JTAG2::CMND_RESET: + case JTAG2::CMND_ENTER_PROGMODE: + JTAG2::enter_progmode(); + break; + case JTAG2::CMND_SIGN_OFF: + // Restore default baud rate before exiting + JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; + case JTAG2::CMND_LEAVE_PROGMODE: + JTAG2::leave_progmode(); + break; + case JTAG2::CMND_GET_SYNC: + case JTAG2::CMND_GO: + JTAG2::set_status(JTAG2::RSP_OK); + break; + case JTAG2::CMND_SET_DEVICE_DESCRIPTOR: + JTAG2::set_device_descriptor(); + break; + case JTAG2::CMND_READ_MEMORY: + JTAG2::read_mem(); + break; + case JTAG2::CMND_WRITE_MEMORY: + JTAG2::write_mem(); + break; + case JTAG2::CMND_XMEGA_ERASE: + JTAG2::erase(); + break; + default: + JTAG2::set_status(JTAG2::RSP_FAILED); + break; + } + // send response + //SYS::LED_blink(2, 5, 100); + JTAG2::answer(); + // some commands need to be executed after sending the answer + JTAG2::delay_exec(); + } + } +} diff --git a/sys.cpp b/sys.cpp new file mode 100644 index 0000000..483b605 --- /dev/null +++ b/sys.cpp @@ -0,0 +1,105 @@ +/* + * sys.cpp + * + * Created: 02-10-2018 13:07:52 + * Author: JMR_2 + */ + +#include +#include +#include + +#include "sys.h" + +void SYS::init(void) { + +#ifndef __AVR_ATmega16__ +# if defined HW_SERIAL +// skip all init, UART used +# elif defined XTINY + // Set clock speed to maximum (default 20MHz, or 16MHz set by fuse) + _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); + /* Disable unused peripherals */ + //ToDo +# else +# if defined(ARDUINO_AVR_LARDU_328E) + clock_prescale_set ( (clock_div_t) __builtin_log2(32000000UL / F_CPU)); +# endif + /* Disable digital input buffers on port C */ + DIDR0 = 0x3F; + /* Disable unused peripherals */ + ACSR = 1 << ACD; // turn off comparator +# endif //HW_SERIAL, XTINY +# ifndef HW_SERIAL + /* Enable all UPDI port pull-ups */ + PORT(UPDI_PORT) = 0xFF; +# endif + /* Enable LED */ + //PORT(LED_PORT) |= (1 << LED_PIN); + /* Enable all LED port pull-ups, except for the LED pin */ + PORT(LED_PORT) = 0xFF - (1 << LED_PIN); +#else + /* No interrupts */ + sei(); + /* Enable all UPDI port pull-ups */ + PORT(UPDI_PORT) = 0xFF; + /* Enable LED */ + PORT(LED_PORT) |= (1 << LED_PIN); + /* Enable all LED port pull-ups, except for the LED pin */ + PORT(LED_PORT) = 0xFF - (1 << LED_PIN); + + + /* Disable unused peripherals */ + SPCR &= ~(1< +#include //for recognizing HW_SERIAL + +//#warning "modify this to match your USB serial port name" +#define SERIALCOM Serial + +// default UART is Serial (HAVE_SERIAL), look for additional ones +// see if additional HW-SERIAL is available, take biggest for UDPI as default +#if defined(HAVE_HWSERIAL3) +# define HW_SERIAL Serial3 +#elif defined(HAVE_HWSERIAL2) +# define HW_SERIAL Serial2 +#elif defined(HAVE_HWSERIAL1) +# define HW_SERIAL Serial1 +#endif + +//#define HW_SERIAL Serial1 + +// if HW_SERIAL exists change UDPI mode +#if defined(HW_SERIAL) +# define UPDI_IO_TYPE 3 +#endif + +// See if we are compiling for an UPDI chip (xmega3 core) +#if __AVR_ARCH__ == 103 +# define XTINY +#endif + +// Auxiliary Macros +#define CONCAT(A,B) A##B +#if defined XTINY +# define PIN(x) CONCAT(VPORT,x).IN +# define PORT(x) CONCAT(VPORT,x).OUT +# define DDR(x) CONCAT(VPORT,x).DIR +#else +# define PIN(x) CONCAT(PIN,x) +# define PORT(x) CONCAT(PORT,x) +# define DDR(x) CONCAT(DDR,x) +#endif + +// Configuration for AVR with additional UART - only LED pin needed, UDPI via UART +#if defined(HW_SERIAL) +// Leonardo / ProMicro PortB, Pin5 = D9 +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 5 +# endif +// Configuration for Arduino Mega +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +# ifndef UPDI_PORT +# define UPDI_PORT D +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 3 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 7 +# endif + +# ifndef UPDI_IO_TYPE +# define UPDI_IO_TYPE 2 +# endif + +// Configuration for AVR-0/1 +#elif defined XTINY +# ifndef UPDI_PORT +# define UPDI_PORT B +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 0 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 1 +# endif + +# ifndef UPDI_IO_TYPE +# define UPDI_IO_TYPE 2 +# endif +// These are currently used only for AVR-0/1 chips +// Select which USART peripheral is being used for host PC communication +// Also, indicate the port/pin of the HOST_USART Tx pin +# ifndef HOST_USART +# define HOST_USART USART0 +# endif + +# ifndef HOST_TX_PORT +# define HOST_TX_PORT B +# endif + +# ifndef HOST_TX_PIN +# define HOST_TX_PIN 2 +# endif + +// Default configuration (suitable for ATmega 328P and similar devices @16MHz) +#else +# ifndef UPDI_PORT +# define UPDI_PORT D +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 6 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 5 +# endif +#endif + + +#ifndef F_CPU +# define F_CPU 16000000U +#endif + +#ifndef UPDI_BAUD +# define UPDI_BAUD 225000U // (max 225000 min approx. F_CPU/100) +#endif + +/* + * Available UPDI I/O types are: + * + * 1 - timer sofware UART: Compatible only with Mega328P and other AVRs with identical 8 bit timer 0. + * Only the OC0A pin can be used for UPDI I/O. Slightly faster upload speed for a given UPDI_BAUD value. + * + * 2 - bitbang software UART: Compatible with many chips and broad choice of UPDI pins are selectable. + * Slightly slower upload speed for a given UPDI_BAUD value. Download speed is the same. + */ +#ifndef UPDI_IO_TYPE +# define UPDI_IO_TYPE 2 +#endif + +// Flash constants class +#if defined XTINY + template + using FLASH = const T; +#else +# include +# define FLASH const PROGMEM flash + + template + class flash { + private: + const T data; + + public: + // normal constructor + constexpr flash (T _data) : data(_data) {} + // default constructor + constexpr flash () : data(0) {} + + operator T() const { + switch (sizeof(T)) { + case 1: return pgm_read_byte(&data); + case 2: return pgm_read_word(&data); + case 4: return pgm_read_dword(&data); + } + } + }; +#endif + +#if defined XTINY + // Note: adapted from MicroChip appnote TB3216 "Getting Started with USART" + constexpr unsigned int baud_reg_val(unsigned long baud) { + return (F_CPU * 64.0) / (16.0 * baud) + 0.5; + } +#else + constexpr unsigned int baud_reg_val(unsigned long baud) { + return F_CPU/(baud * 8.0) - 0.5; + } +#endif + +namespace SYS { + void init(void); + void setLED(void); + void clearLED(void); + void LED_blink (int led_no, int led_blinks, int length_ms); +} + +#endif /* SYS_H_ */ diff --git a/updi_io.cpp b/updi_io.cpp new file mode 100644 index 0000000..8e9db80 --- /dev/null +++ b/updi_io.cpp @@ -0,0 +1,224 @@ +/* + * updi_io.cpp + * + * Created: 18-11-2017 10:36:54 + * Author: JMR_2 + */ + + + +// Includes +#include +#include "updi_io.h" +#include "sys.h" + +#if UPDI_IO_TYPE == 1 + +// Cycle timing +#define BIT_TIME (F_CPU/UPDI_BAUD) + +// Local functions +namespace { + void setup_bit_low(); + void setup_bit_high(); + void wait_for_bit() __attribute__((always_inline)); + void stop_timer(); + void start_timer(); +} + +// Enable to get pulses on PD7 showing the sample times for the software UART input +//#define _DEBUG + +// Functions +/* Sends regular characters through the UPDI link */ +uint8_t UPDI_io::put(char c) { + /* Wait for end of stop bits */ + wait_for_bit(); + stop_timer(); + /* Send start bit */ + OCR0A = BIT_TIME - 1; + TCNT0 = BIT_TIME - 2; + setup_bit_low(); + start_timer(); + /* Enable TX output */ + DDR(UPDI_PORT) |= (1 << UPDI_PIN); + /* Calculate parity */ + uint8_t parity; //get_parity(c); + parity = 0; + /* If we can be sure an overflow has happened by now due to instruction latency, */ + /* no more wait is needed and we only need to clear overflow flag */ + //wait_for_bit(); + TIFR0 = (1 << OCF0A); + /* Send data bits and calculate parity */ + for (uint8_t mask = 1; mask; mask <<= 1) { + // Check bit, transmit high or low bit accordingly and update parity bit + parity = (c & mask) ? (setup_bit_high(), ~parity) : (setup_bit_low(), parity); + wait_for_bit(); + } + /* Send parity bit */ + parity ? setup_bit_high() : setup_bit_low(); + wait_for_bit(); + /* Send stop bits */ + setup_bit_high(); + wait_for_bit(); + OCR0A = 2 * BIT_TIME - 1; // 2 bits + /* Ready for RX input, but high due to pull-up */ + DDR(UPDI_PORT) &= ~(1 << UPDI_PIN); + return c; +} + +/* Sends special sequences through the UPDI link */ +uint8_t UPDI_io::put(ctrl c) +{ + /* This nested function expects the timer output to just have gone low */ + /* It waits for 12 minimum baud bit times (break character) then goes high */ + auto break_pulse = [] { + TCCR0B = 4; // timer tick = 256/F_CPU seconds + OCR0A = F_CPU/125000; // bit time = F_CPU/125000 ticks ~ 2.048 ms + for (uint8_t i = 0; i < 11; i++) wait_for_bit(); // 12 bits ~ 24.6 ms, as recommended on the datasheet + setup_bit_high(); + wait_for_bit(); + DDR(UPDI_PORT) &= ~(1 << UPDI_PIN); + }; + + stop_timer(); + /* Send falling edge */ + OCR0A = BIT_TIME - 1; + TCNT0 = BIT_TIME - 2; + setup_bit_low(); + start_timer(); + /* Enable TX output */ + DDR(UPDI_PORT) |= (1 << UPDI_PIN); + /* clear overflow flag */ + TIFR0 = (1 << OCF0A); + switch (c) { + case double_break: + break_pulse(); + setup_bit_low(); + wait_for_bit(); + DDR(UPDI_PORT) |= (1 << UPDI_PIN); + case single_break: + break_pulse(); + wait_for_bit(); + break; + case enable: + /* + TCCR0A = 0; + DDRD |= (1 << DDD6); + PORTD &= ~(1 << DDD6); + __builtin_avr_nops(5); + PORTD |= (1 << DDD6); + DDRD &= ~(1 << DDD6); + setup_bit_high(); + break; + */ + default: + break; + } + OCR0A = BIT_TIME - 1; + TCNT0 = BIT_TIME - 2; + start_timer(); + return 0; +} + +uint8_t UPDI_io::get() { + stop_timer(); + /* Wait for middle of start bit */ + OCR0A = BIT_TIME / 2 - 1; + TCNT0 = 12; // overhead time; needs to be calibrated + /* Make sure overflow flag is reset */ + TIFR0 = (1 << OCF0A); + + /* Must disable pull-up, because the UPDI UART just sends very short output pulses at the beginning of each bit time. */ + /* If pull up is enabled, there will be a drift to high state that results in erroneous input sampling. */ + /* As a side effect, random electrical fluctuations of the input prevent an infinite wait loop */ + /* in case no target is connected. */ + PORT(UPDI_PORT) &= ~(1 << UPDI_PIN); + /* Wait for start bit */ + loop_until_bit_is_clear(PIN(UPDI_PORT), UPDI_PIN); + + start_timer(); + wait_for_bit(); + /* Setup sampling time */ + OCR0A = BIT_TIME - 1; +# ifdef _DEBUG + /* Timing pulse */ + PIND |= (1 << PIND7); + PIND |= (1 << PIND7); +# endif // _DEBUG + /* Sample bits */ + uint8_t c = 0; + //for (uint8_t i = 0; i < 8; i++) { + for (uint8_t mask = 1; mask; mask <<= 1) { + wait_for_bit(); + /* Take sample */ + //c /= 2; + if ( PIN(UPDI_PORT) & (1 << UPDI_PIN) ) { + //c |= 0x80; + c |= mask; + } +# ifdef _DEBUG + /* Timing pulse */ + PIND |= (1 << PIND7); + PIND |= (1 << PIND7); +# endif // _DEBUG + } + /* To Do Sample Parity */ + wait_for_bit(); +# ifdef _DEBUG + /* Timing pulse */ + PIND |= (1 << PIND7); + PIND |= (1 << PIND7); +# endif // _DEBUG + OCR0A = 2 * BIT_TIME + BIT_TIME / 2 - 1; // 2.5 bits + /* Return as soon as high parity or stop bits start */ + loop_until_bit_is_set(PIN(UPDI_PORT), UPDI_PIN); + /* Re-enable pull up */ + PORT(UPDI_PORT) |= (1 << UPDI_PIN); + return c; +} + +void UPDI_io::init(void) +{ +# ifdef _DEBUG + /* For RX timing measurement and debugging, make PD7 output */ + DDRD |= (1 << DDD7); +# endif // _DEBUG + setup_bit_high(); + /* initialize counter to near terminal count */ + TCNT0 = BIT_TIME - 2; + /* initialize OCR0A to 200k counts per second */ + OCR0A = BIT_TIME - 1; + start_timer(); +} + +namespace { + inline void setup_bit_low() { + /* OC0A will go low on match with OCR0A */ + /* Also, set CTC mode - reset timer on match with OCR0A */ + TCCR0A = (1 << COM0A1) | (0 << COM0A0) | (1 << WGM01); + } + + inline void setup_bit_high() { + /* OC0A will go high on match with OCR0A */ + /* Also, set CTC mode - reset timer on match with OCR0A */ + TCCR0A = (1 << COM0A1) | (1 << COM0A0) | (1 << WGM01); + } + + inline void wait_for_bit() { + /* Wait for compare match */ + loop_until_bit_is_set(TIFR0, OCF0A); + TIFR0 = (1 << OCF0A); + } + + inline void stop_timer() { + TCCR0B = 0; + } + + inline void start_timer() { + TCCR0B = 1; + } +} + + +#endif //UPDI_IO_TYPE == 1 diff --git a/updi_io_uart.cpp b/updi_io_uart.cpp new file mode 100644 index 0000000..91a722b --- /dev/null +++ b/updi_io_uart.cpp @@ -0,0 +1,73 @@ +/* + * updi_io_uart.cpp + * + * Created: 01-02-2020 10:36:54 + * Author: cherry pick from AvrMega_MuxTO + */ + + + +// Includes +#include +#include "updi_io.h" +#include "sys.h" + + +#if UPDI_IO_TYPE == 3 +#include + +// Functions +/* Sends regular characters through the UPDI link */ +uint8_t UPDI_io::put(char c) { + HW_SERIAL.write(c); + HW_SERIAL.flush(); + //delayMicroseconds(10); + long start = millis(); + while (!HW_SERIAL.available() && millis() - start < 20) {} + char d = HW_SERIAL.read(); + if (c != d) { + // Serial.println("echo failed! " + String(d, HEX)); + } + return c; +} + +/* Sends special sequences through the UPDI link */ +uint8_t UPDI_io::put(ctrl c) +{ + HW_SERIAL.begin(300, SERIAL_8N1); + switch (c) { + case double_break: + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + break; + case single_break: + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + break; + default: + break; + } + delay(15); + while (HW_SERIAL.available()) { + HW_SERIAL.read(); + } + HW_SERIAL.begin(230400, SERIAL_8E2); + return 0; +} + +uint8_t UPDI_io::get() { + uint8_t c; + while (!HW_SERIAL.available()) {} + c = HW_SERIAL.read(); + //delayMicroseconds(5); + //Serial.println("get! " + String(c, HEX)); + return c; +} + +void UPDI_io::init(void) +{ + HW_SERIAL.begin(230400, SERIAL_8E2); +} +#endif //UPDI_IO_TYPE == 3 diff --git a/updi_io_uart.h b/updi_io_uart.h new file mode 100644 index 0000000..d72b85e --- /dev/null +++ b/updi_io_uart.h @@ -0,0 +1,25 @@ +/* + * updi_io.h + * + * Created: 18-11-2017 10:38:31 + * Author: JMR_2 + */ + + +#ifndef UPDI_IO_H_ +#define UPDI_IO_H_ + +#include + +namespace UPDI_io { + // Enums + enum ctrl {single_break, double_break, enable}; + + // Function prototypes + uint8_t put(char) __attribute__((optimize("no-tree-loop-optimize"))); + uint8_t put(ctrl); + uint8_t get() __attribute__((optimize("no-tree-loop-optimize"))); + void init(void); +} + +#endif /* UPDI_IO_H_ */ \ No newline at end of file From e36cb3c702d70601893a79066c140a2481cb15b5 Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 18 Feb 2020 09:20:48 +0100 Subject: [PATCH 06/14] Delete JICE_io.cpp messed up commit: wrong directory --- JICE_io.cpp | 119 ---------------------------------------------------- 1 file changed, 119 deletions(-) delete mode 100644 JICE_io.cpp diff --git a/JICE_io.cpp b/JICE_io.cpp deleted file mode 100644 index 76f709d..0000000 --- a/JICE_io.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * stk_io.cpp - * - * Created: 18-11-2017 15:20:29 - * Author: JMR_2 - */ - -// Includes -#include -#include -#include "JICE_io.h" -#include "sys.h" - -namespace { - // *** Baud rate lookup table for UBRR0 register *** - // Indexed by valid values for PARAM_BAUD_RATE_VAL (defined in JTAG2.h) - FLASH baud_tbl[8] = {baud_reg_val(2400), baud_reg_val(4800), baud_reg_val(9600), baud_reg_val(19200), baud_reg_val(38400), baud_reg_val(57600), baud_reg_val(115200), baud_reg_val(14400)}; -} - -// Functions -uint8_t JICE_io::put(char c) { -#ifdef __AVR_ATmega16__ - loop_until_bit_is_set(UCSRA, UDRE); - return UDR = c; -#elif defined XTINY - loop_until_bit_is_set(HOST_USART.STATUS, USART_DREIF_bp); - return HOST_USART.TXDATAL = c; -#elif defined __AVR_ATmega32U4__ - // wait for Serial to be active - // while (!SERIALCOM); - // commented out: timeout/error communicating with programmer (status -1) - SERIALCOM.write(c); - return c; -#else - loop_until_bit_is_set(UCSR0A, UDRE0); - return UDR0 = c; -#endif -} - -uint8_t JICE_io::get(void) { -#ifdef __AVR_ATmega16__ - loop_until_bit_is_set(UCSRA, RXC); /* Wait until data exists. */ - return UDR; -#elif defined XTINY - loop_until_bit_is_set(HOST_USART.STATUS, USART_RXCIF_bp); /* Wait until data exists. */ - return HOST_USART.RXDATAL; -#elif defined __AVR_ATmega32U4__ - uint8_t c = SERIALCOM.read(); - return c; -#else - loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ - return UDR0; -#endif -} - -void JICE_io::init(void) { -#ifdef __AVR_ATmega16__ - /* Set double speed */ - UCSRA = (1< Date: Tue, 18 Feb 2020 09:21:00 +0100 Subject: [PATCH 07/14] Delete JTAG2.cpp messed up commit: wrong directory --- JTAG2.cpp | 376 ------------------------------------------------------ 1 file changed, 376 deletions(-) delete mode 100644 JTAG2.cpp diff --git a/JTAG2.cpp b/JTAG2.cpp deleted file mode 100644 index 171e1cf..0000000 --- a/JTAG2.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * STK500.cpp - * - * Created: 08-12-2017 19:47:27 - * Author: JMR_2 - */ - -#include "JTAG2.h" -#include "JICE_io.h" -#include "NVM.h" -#include "crc16.h" -#include "UPDI_hi_lvl.h" - -// *** Writeable Parameter Values *** -uint8_t JTAG2::PARAM_EMU_MODE_VAL; -JTAG2::baud_rate JTAG2::PARAM_BAUD_RATE_VAL; - -// *** STK500 packet *** -JTAG2::packet_t JTAG2::packet; - -namespace { - // *** Private variables *** - uint8_t flash_pagesize; - uint8_t eeprom_pagesize; - - // *** Local functions declaration *** - void NVM_fuse_write (uint16_t address, uint8_t data); - void NVM_buffered_write(uint16_t address, uint16_t lenght, uint8_t buff_size, uint8_t write_type); -} - -// *** Packet functions *** - bool JTAG2::receive() { - while (JICE_io::get() != MESSAGE_START); - uint16_t crc = CRC::next(MESSAGE_START); - for (uint16_t i = 0; i < 6; i++) { - crc = CRC::next(packet.raw[i] = JICE_io::get(), crc); - } - if (packet.size_word[0] > sizeof(packet.body)) return false; - if (JICE_io::get() != TOKEN) return false; - crc = CRC::next(TOKEN, crc); - for (uint16_t i = 0; i < packet.size_word[0]; i++) { - crc = CRC::next(packet.body[i] = JICE_io::get(), crc); - } - if ((uint16_t)(JICE_io::get() | (JICE_io::get() << 8)) != crc) return false; - return true; - } - - void JTAG2::answer() { - uint16_t crc = CRC::next(JICE_io::put(MESSAGE_START)); - for (uint16_t i = 0; i < 6; i++) { - crc = CRC::next(JICE_io::put(packet.raw[i]), crc); - } - crc = CRC::next(JICE_io::put(TOKEN), crc); - for (uint16_t i = 0; i < packet.size_word[0]; i++) { - crc = CRC::next(JICE_io::put(packet.body[i]), crc); - } - JICE_io::put(crc); - JICE_io::put(crc >> 8); - } - - void JTAG2::delay_exec() { - // wait for transmission complete - JICE_io::flush(); - // set baud rate - JICE_io::set_baud(PARAM_BAUD_RATE_VAL); - } - -// *** Set status function *** - void JTAG2::set_status(uint8_t status_code){ - packet.size_word[0] = 1; - packet.body[0] = status_code; - } - -// *** General command functions *** - // *** Signature response message *** - FLASH JTAG2::sgn_resp[29] { 0x86, 1, - 1, PARAM_FW_VER_M_MIN_VAL, PARAM_FW_VER_M_MAJ_VAL, PARAM_HW_VER_M_VAL, - 1, PARAM_FW_VER_S_MIN_VAL, PARAM_FW_VER_S_MAJ_VAL, PARAM_HW_VER_S_VAL, - 0, 0, 0, 0, 0, 0, - 'J', 'T', 'A', 'G', 'I', 'C', 'E', ' ', 'm', 'k', 'I', 'I', 0}; - void JTAG2::sign_on(){ - // Initialize JTAGICE2 variables - JTAG2::PARAM_EMU_MODE_VAL = 0x02; - JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; - /* Initialize or enable UPDI */ - UPDI_io::put(UPDI_io::double_break); -#if UPDI_IO_TYPE == 3 - // use timing from MEGA_AVR project, but worked with timing from bitbang as well - - // Timing Type3 - UPDI UART - // Bit 3 - Collision and Contention Detection Disable - UPDI::stcs(UPDI::reg::Control_B, 8); - // Bit 7 – IBDLY Inter-Byte Delay Enable - // Bit 5=0 Parity enable - // Bit 4=0 Time-out detection enable - // Bit 3=0 RSD Response Signature Enable - // Bit 2:0 0x0 UPDI Guard Time: 128 cycles (default) - UPDI::stcs(UPDI::reg::Control_A, 0x80); - //UPDI::stcs(UPDI::reg::Control_A, 6); -#else - // Timing Type1 UPDI bitbang - // UPDI Guard Time: 2 cycles - UPDI::stcs(UPDI::reg::Control_A, 6); -#endif - // Send sign on message - packet.size_word[0] = sizeof(sgn_resp); - for (uint8_t i = 0; i < sizeof(sgn_resp); i++) { - packet.body[i] = sgn_resp[i]; - } - } - - void JTAG2::get_parameter(){ - uint8_t & status = packet.body[0]; - uint8_t & parameter = packet.body[1]; - switch (parameter) { - case PARAM_HW_VER: - packet.size_word[0] = 3; - packet.body[1] = PARAM_HW_VER_M_VAL; - packet.body[2] = PARAM_HW_VER_S_VAL; - break; - case PARAM_FW_VER: - packet.size_word[0] = 5; - packet.body[1] = PARAM_FW_VER_M_MIN_VAL; - packet.body[2] = PARAM_FW_VER_M_MAJ_VAL; - packet.body[3] = PARAM_FW_VER_S_MIN_VAL; - packet.body[4] = PARAM_FW_VER_S_MAJ_VAL; - break; - case PARAM_EMU_MODE: - packet.size_word[0] = 2; - packet.body[1] = PARAM_EMU_MODE_VAL; - break; - case PARAM_BAUD_RATE: - packet.size_word[0] = 2; - packet.body[1] = PARAM_BAUD_RATE_VAL; - break; - case PARAM_VTARGET: - packet.size_word[0] = 3; - packet.body[1] = PARAM_VTARGET_VAL & 0xFF; - packet.body[2] = PARAM_VTARGET_VAL >> 8; - break; - default: - set_status(RSP_ILLEGAL_PARAMETER); - return; - } - status = RSP_PARAMETER; - return; - } - - void JTAG2::set_parameter(){ - uint8_t & parameter = packet.body[1]; - switch (parameter) { - case PARAM_EMU_MODE: - PARAM_EMU_MODE_VAL = packet.body[2]; - break; - case PARAM_BAUD_RATE: - PARAM_BAUD_RATE_VAL = (baud_rate)packet.body[2]; - break; - default: - set_status(RSP_ILLEGAL_PARAMETER); - return; - } - set_status(RSP_OK); - } - - void JTAG2::set_device_descriptor(){ - flash_pagesize = packet.body[244]; - eeprom_pagesize = packet.body[246]; - set_status(RSP_OK); - } - -// *** Target mode set functions *** - // *** Sets MCU in program mode, if possibe *** - void JTAG2::enter_progmode(){ - // Reset the MCU now, to prevent the WDT (if active) to reset it at an unpredictable moment - UPDI::CPU_reset(); - // Now we have time to enter program mode (this mode also disables the WDT) - const uint8_t system_status = UPDI::CPU_mode<0xEF>(); - switch (system_status){ - // in normal operation mode - case 0x82: - // Write NVN unlock key (allows read access to all addressing space) - UPDI::write_key(UPDI::NVM_Prog); - // Request reset - UPDI::CPU_reset(); - // Wait for NVM unlock state - //while (UPDI::CPU_mode() != 0x08); - // already in program mode - case 0x08: - // better clear the page buffer, just in case. - UPDI::sts_b(NVM::NVM_base | NVM::CTRLA, NVM::PBC); - // Turn on LED to indicate program mode - SYS::setLED(); - set_status(RSP_OK); - break; - // in other modes fail and inform host of wrong mode - default: - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = system_status; // 0x01; - } - } - - // *** Sets MCU in normal runnning mode, if possibe *** - void JTAG2::leave_progmode(){ - const uint8_t system_status = UPDI::CPU_mode<0xEF>(); - switch (system_status){ - // in program mode - case 0x08: - // Request reset - UPDI::CPU_reset(); - // Wait for normal mode - // while (UPDI::CPU_mode<0xEF>() != 0x82); - // already in normal mode - case 0x82: - // Turn off LED to indicate normal mode - SYS::clearLED(); - set_status(RSP_OK); - break; - // in other modes fail and inform host of wrong mode - default: - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = system_status; // 0x01; - } - } - -// *** Read/Write/Erase functions *** - - void JTAG2::read_mem() { - if (UPDI::CPU_mode() != 0x08){ - // fail if not in program mode - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = 0x01; - } - else { - // in program mode - const uint16_t NumBytes = (packet.body[3] << 8) | packet.body[2]; - // Get physical address for reading - const uint16_t address = (packet.body[7] << 8) | packet.body[6]; - // Set UPDI pointer to address - UPDI::stptr_w(address); - // Read block - UPDI::rep(NumBytes - 1); - packet.body[1] = UPDI::ldinc_b(); - for (uint16_t i = 2; i <= NumBytes; i++) { - packet.body[i] = UPDI_io::get(); - } - packet.size_word[0] = NumBytes + 1; - packet.body[0] = RSP_MEMORY; - } - } - - void JTAG2::write_mem() { - if (UPDI::CPU_mode() != 0x08){ - // fail if not in program mode - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = 0x01; - } - else { - // in program mode - const uint8_t mem_type = packet.body[1]; - const uint16_t address = packet.body[6] | (packet.body[7] << 8); - const uint16_t lenght = packet.body[2] | (packet.body[3] << 8); /* number of bytes to write */ - const bool is_flash = ((mem_type == MTYPE_FLASH) || (mem_type == MTYPE_BOOT_FLASH)); - const uint8_t buff_size = is_flash ? flash_pagesize : eeprom_pagesize; - const uint8_t write_cmnd = is_flash ? NVM::WP : NVM::ERWP; - switch (mem_type) { - case MTYPE_FUSE_BITS: - case MTYPE_LOCK_BITS: - NVM_fuse_write (address, packet.body[10]); - break; - case MTYPE_FLASH: - case MTYPE_BOOT_FLASH: - case MTYPE_EEPROM_XMEGA: - case MTYPE_USERSIG: - NVM_buffered_write(address, lenght, buff_size, write_cmnd); - break; - default: - set_status(RSP_ILLEGAL_MEMORY_TYPE); - return; - } - set_status(RSP_OK); - } - } - - void JTAG2::erase() { - const uint8_t erase_type = packet.body[1]; - const uint16_t address = packet.body[2] | (packet.body[3] << 8); - switch (erase_type) { - case 0: - // Write Chip Erase key - UPDI::write_key(UPDI::Chip_Erase); - // Request reset - UPDI::CPU_reset(); - // Erase chip process exits program mode, reenter... - enter_progmode(); - break; - case 4: - case 5: - NVM::wait(); - UPDI::sts_b(address, 0xFF); - NVM::command(NVM::ER); - set_status(RSP_OK); - break; - case 6: - case 7: - break; - default: - set_status(RSP_FAILED); - } - } - -// *** Local functions definition *** -namespace { - void NVM_fuse_write (uint16_t address, uint8_t data) { - // Setup UPDI pointer - UPDI::stptr_w(NVM::NVM_base + NVM::DATA_lo); - // Send data to the NVM controller - UPDI::stinc_b(data); - UPDI::stinc_b(0x00); - // Send address to the NVM controller - UPDI::stinc_b(address & 0xFF); - UPDI::stinc_b(address >> 8); - // Execute fuse write - NVM::command(NVM::WFU); - } - - void NVM_buffered_write(const uint16_t address, const uint16_t length, const uint8_t buff_size, const uint8_t write_cmnd) { - uint8_t current_byte_index = 10; /* Index of the first byte to send inside the JTAG2 command body */ - uint16_t bytes_remaining = length; /* number of bytes to write */ - - // Sends a block of bytes from the command body to memory, using the UPDI interface - // On entry, the UPDI pointer must already point to the desired address - // On exit, the UPDI pointer points to the next byte after the last one written - // Returns updated index into the command body, pointing to the first unsent byte. - auto updi_send_block = [] (uint8_t count, uint8_t index) { - count--; - NVM::wait(); - UPDI::rep(count); - UPDI::stinc_b(JTAG2::packet.body[index]); - for (uint8_t i = count; i; i--) { - UPDI_io::put(JTAG2::packet.body[++index]); - UPDI_io::get(); - } - return ++index; - }; - - // Setup UPDI pointer for block transfer - UPDI::stptr_w(address); - /* Check address alignment, calculate number of unaligned bytes to send */ - uint8_t unaligned_bytes = (-address & (buff_size - 1)); - if (unaligned_bytes > bytes_remaining) unaligned_bytes = bytes_remaining; - /* If there are unaligned bytes, they must be sent first */ - if (unaligned_bytes) { - // Send unaligned block - current_byte_index = updi_send_block(unaligned_bytes, current_byte_index); - bytes_remaining -= unaligned_bytes; - NVM::command(write_cmnd); - } - while (bytes_remaining) { - /* Send a buff_size amount of bytes */ - if (bytes_remaining >= buff_size) { - current_byte_index = updi_send_block(buff_size, current_byte_index); - bytes_remaining -= buff_size; - } - /* Send a NumBytes amount of bytes */ - else { - current_byte_index = updi_send_block(bytes_remaining, current_byte_index); - bytes_remaining = 0; - } - NVM::command(write_cmnd); - } - } -} From 6b73ce3e60708b895cd5d81eb20fd656c629b4e2 Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 18 Feb 2020 09:22:21 +0100 Subject: [PATCH 08/14] Delete jtag2updi.cpp messed up commit: wrong directory --- jtag2updi.cpp | 121 -------------------------------------------------- 1 file changed, 121 deletions(-) delete mode 100644 jtag2updi.cpp diff --git a/jtag2updi.cpp b/jtag2updi.cpp deleted file mode 100644 index 4caea0a..0000000 --- a/jtag2updi.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * j2updi.cpp - * - * Created: 11-11-2017 22:29:58 - * Author : JMR_2 - */ - -// Includes -#if defined __AVR_ATmega32U4__ - #include - #include "USBAPI.h" - -// Declared weak in Arduino.h to allow user redefinitions. - int atexit(void (* /*func*/ )()) { return 0; } - -// Weak empty variant initialization function. -// May be redefined by variant files. - void initVariant() __attribute__((weak)); - void initVariant() { } - - void setupUSB() __attribute__((weak)); - void setupUSB() { } - -#endif - -#include "sys.h" -#if UPDI_IO_TYPE==3 - #include "updi_io_uart.h" -#else - #include "updi_io.h" -#endif -#include "JICE_io.h" -#include "JTAG2.h" - -/* Internal stuff */ -namespace { - // Prototypes - void setup2(); - void loop2(); -} - -int main(void) -{ - #if defined __AVR_ATmega32U4__ - init(); - initVariant(); - #endif - - #if defined(USBCON) - USBDevice.attach(); - #endif - setup2(); - loop2(); -} - -/* Internal stuff */ -namespace { - inline void setup2() { - /* Initialize MCU */ - SYS::init(); - - /* Initialize serial links */ - JICE_io::init(); - UPDI_io::init(); - } - - - inline void loop2() { - while (1) { - - // Receive command - while(!JTAG2::receive()); - // Process command - switch (JTAG2::packet.body[0]) { - case JTAG2::CMND_GET_SIGN_ON: - JTAG2::sign_on(); - break; - case JTAG2::CMND_GET_PARAMETER: - JTAG2::get_parameter(); - break; - case JTAG2::CMND_SET_PARAMETER: - JTAG2::set_parameter(); - break; - case JTAG2::CMND_RESET: - case JTAG2::CMND_ENTER_PROGMODE: - JTAG2::enter_progmode(); - break; - case JTAG2::CMND_SIGN_OFF: - // Restore default baud rate before exiting - JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; - case JTAG2::CMND_LEAVE_PROGMODE: - JTAG2::leave_progmode(); - break; - case JTAG2::CMND_GET_SYNC: - case JTAG2::CMND_GO: - JTAG2::set_status(JTAG2::RSP_OK); - break; - case JTAG2::CMND_SET_DEVICE_DESCRIPTOR: - JTAG2::set_device_descriptor(); - break; - case JTAG2::CMND_READ_MEMORY: - JTAG2::read_mem(); - break; - case JTAG2::CMND_WRITE_MEMORY: - JTAG2::write_mem(); - break; - case JTAG2::CMND_XMEGA_ERASE: - JTAG2::erase(); - break; - default: - JTAG2::set_status(JTAG2::RSP_FAILED); - break; - } - // send response - //SYS::LED_blink(2, 5, 100); - JTAG2::answer(); - // some commands need to be executed after sending the answer - JTAG2::delay_exec(); - } - } -} From f3e62ef378a10e5866fd8916f2adad13f09990ff Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 18 Feb 2020 09:23:03 +0100 Subject: [PATCH 09/14] Delete sys.cpp messed up commit: wrong directory --- sys.cpp | 105 -------------------------------------------------------- 1 file changed, 105 deletions(-) delete mode 100644 sys.cpp diff --git a/sys.cpp b/sys.cpp deleted file mode 100644 index 483b605..0000000 --- a/sys.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * sys.cpp - * - * Created: 02-10-2018 13:07:52 - * Author: JMR_2 - */ - -#include -#include -#include - -#include "sys.h" - -void SYS::init(void) { - -#ifndef __AVR_ATmega16__ -# if defined HW_SERIAL -// skip all init, UART used -# elif defined XTINY - // Set clock speed to maximum (default 20MHz, or 16MHz set by fuse) - _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); - /* Disable unused peripherals */ - //ToDo -# else -# if defined(ARDUINO_AVR_LARDU_328E) - clock_prescale_set ( (clock_div_t) __builtin_log2(32000000UL / F_CPU)); -# endif - /* Disable digital input buffers on port C */ - DIDR0 = 0x3F; - /* Disable unused peripherals */ - ACSR = 1 << ACD; // turn off comparator -# endif //HW_SERIAL, XTINY -# ifndef HW_SERIAL - /* Enable all UPDI port pull-ups */ - PORT(UPDI_PORT) = 0xFF; -# endif - /* Enable LED */ - //PORT(LED_PORT) |= (1 << LED_PIN); - /* Enable all LED port pull-ups, except for the LED pin */ - PORT(LED_PORT) = 0xFF - (1 << LED_PIN); -#else - /* No interrupts */ - sei(); - /* Enable all UPDI port pull-ups */ - PORT(UPDI_PORT) = 0xFF; - /* Enable LED */ - PORT(LED_PORT) |= (1 << LED_PIN); - /* Enable all LED port pull-ups, except for the LED pin */ - PORT(LED_PORT) = 0xFF - (1 << LED_PIN); - - - /* Disable unused peripherals */ - SPCR &= ~(1< Date: Tue, 18 Feb 2020 09:23:16 +0100 Subject: [PATCH 10/14] Delete sys.h messed up commit: wrong directory --- sys.h | 207 ---------------------------------------------------------- 1 file changed, 207 deletions(-) delete mode 100644 sys.h diff --git a/sys.h b/sys.h deleted file mode 100644 index 14fe61e..0000000 --- a/sys.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * sys.h - * - * Created: 02-10-2018 13:07:18 - * Author: JMR_2 - */ - -#ifndef SYS_H_ -#define SYS_H_ - -#include -#include //for recognizing HW_SERIAL - -//#warning "modify this to match your USB serial port name" -#define SERIALCOM Serial - -// default UART is Serial (HAVE_SERIAL), look for additional ones -// see if additional HW-SERIAL is available, take biggest for UDPI as default -#if defined(HAVE_HWSERIAL3) -# define HW_SERIAL Serial3 -#elif defined(HAVE_HWSERIAL2) -# define HW_SERIAL Serial2 -#elif defined(HAVE_HWSERIAL1) -# define HW_SERIAL Serial1 -#endif - -//#define HW_SERIAL Serial1 - -// if HW_SERIAL exists change UDPI mode -#if defined(HW_SERIAL) -# define UPDI_IO_TYPE 3 -#endif - -// See if we are compiling for an UPDI chip (xmega3 core) -#if __AVR_ARCH__ == 103 -# define XTINY -#endif - -// Auxiliary Macros -#define CONCAT(A,B) A##B -#if defined XTINY -# define PIN(x) CONCAT(VPORT,x).IN -# define PORT(x) CONCAT(VPORT,x).OUT -# define DDR(x) CONCAT(VPORT,x).DIR -#else -# define PIN(x) CONCAT(PIN,x) -# define PORT(x) CONCAT(PORT,x) -# define DDR(x) CONCAT(DDR,x) -#endif - -// Configuration for AVR with additional UART - only LED pin needed, UDPI via UART -#if defined(HW_SERIAL) -// Leonardo / ProMicro PortB, Pin5 = D9 -# ifndef LED_PORT -# define LED_PORT B -# endif - -# ifndef LED_PIN -# define LED_PIN 5 -# endif -// Configuration for Arduino Mega -#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -# ifndef UPDI_PORT -# define UPDI_PORT D -# endif - -# ifndef UPDI_PIN -# define UPDI_PIN 3 -# endif - -# ifndef LED_PORT -# define LED_PORT B -# endif - -# ifndef LED_PIN -# define LED_PIN 7 -# endif - -# ifndef UPDI_IO_TYPE -# define UPDI_IO_TYPE 2 -# endif - -// Configuration for AVR-0/1 -#elif defined XTINY -# ifndef UPDI_PORT -# define UPDI_PORT B -# endif - -# ifndef UPDI_PIN -# define UPDI_PIN 0 -# endif - -# ifndef LED_PORT -# define LED_PORT B -# endif - -# ifndef LED_PIN -# define LED_PIN 1 -# endif - -# ifndef UPDI_IO_TYPE -# define UPDI_IO_TYPE 2 -# endif -// These are currently used only for AVR-0/1 chips -// Select which USART peripheral is being used for host PC communication -// Also, indicate the port/pin of the HOST_USART Tx pin -# ifndef HOST_USART -# define HOST_USART USART0 -# endif - -# ifndef HOST_TX_PORT -# define HOST_TX_PORT B -# endif - -# ifndef HOST_TX_PIN -# define HOST_TX_PIN 2 -# endif - -// Default configuration (suitable for ATmega 328P and similar devices @16MHz) -#else -# ifndef UPDI_PORT -# define UPDI_PORT D -# endif - -# ifndef UPDI_PIN -# define UPDI_PIN 6 -# endif - -# ifndef LED_PORT -# define LED_PORT B -# endif - -# ifndef LED_PIN -# define LED_PIN 5 -# endif -#endif - - -#ifndef F_CPU -# define F_CPU 16000000U -#endif - -#ifndef UPDI_BAUD -# define UPDI_BAUD 225000U // (max 225000 min approx. F_CPU/100) -#endif - -/* - * Available UPDI I/O types are: - * - * 1 - timer sofware UART: Compatible only with Mega328P and other AVRs with identical 8 bit timer 0. - * Only the OC0A pin can be used for UPDI I/O. Slightly faster upload speed for a given UPDI_BAUD value. - * - * 2 - bitbang software UART: Compatible with many chips and broad choice of UPDI pins are selectable. - * Slightly slower upload speed for a given UPDI_BAUD value. Download speed is the same. - */ -#ifndef UPDI_IO_TYPE -# define UPDI_IO_TYPE 2 -#endif - -// Flash constants class -#if defined XTINY - template - using FLASH = const T; -#else -# include -# define FLASH const PROGMEM flash - - template - class flash { - private: - const T data; - - public: - // normal constructor - constexpr flash (T _data) : data(_data) {} - // default constructor - constexpr flash () : data(0) {} - - operator T() const { - switch (sizeof(T)) { - case 1: return pgm_read_byte(&data); - case 2: return pgm_read_word(&data); - case 4: return pgm_read_dword(&data); - } - } - }; -#endif - -#if defined XTINY - // Note: adapted from MicroChip appnote TB3216 "Getting Started with USART" - constexpr unsigned int baud_reg_val(unsigned long baud) { - return (F_CPU * 64.0) / (16.0 * baud) + 0.5; - } -#else - constexpr unsigned int baud_reg_val(unsigned long baud) { - return F_CPU/(baud * 8.0) - 0.5; - } -#endif - -namespace SYS { - void init(void); - void setLED(void); - void clearLED(void); - void LED_blink (int led_no, int led_blinks, int length_ms); -} - -#endif /* SYS_H_ */ From f5fad3d856111dd4a4fb4458793ebfd5d25385df Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 18 Feb 2020 09:23:27 +0100 Subject: [PATCH 11/14] Delete updi_io.cpp messed up commit: wrong directory --- updi_io.cpp | 224 ---------------------------------------------------- 1 file changed, 224 deletions(-) delete mode 100644 updi_io.cpp diff --git a/updi_io.cpp b/updi_io.cpp deleted file mode 100644 index 8e9db80..0000000 --- a/updi_io.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * updi_io.cpp - * - * Created: 18-11-2017 10:36:54 - * Author: JMR_2 - */ - - - -// Includes -#include -#include "updi_io.h" -#include "sys.h" - -#if UPDI_IO_TYPE == 1 - -// Cycle timing -#define BIT_TIME (F_CPU/UPDI_BAUD) - -// Local functions -namespace { - void setup_bit_low(); - void setup_bit_high(); - void wait_for_bit() __attribute__((always_inline)); - void stop_timer(); - void start_timer(); -} - -// Enable to get pulses on PD7 showing the sample times for the software UART input -//#define _DEBUG - -// Functions -/* Sends regular characters through the UPDI link */ -uint8_t UPDI_io::put(char c) { - /* Wait for end of stop bits */ - wait_for_bit(); - stop_timer(); - /* Send start bit */ - OCR0A = BIT_TIME - 1; - TCNT0 = BIT_TIME - 2; - setup_bit_low(); - start_timer(); - /* Enable TX output */ - DDR(UPDI_PORT) |= (1 << UPDI_PIN); - /* Calculate parity */ - uint8_t parity; //get_parity(c); - parity = 0; - /* If we can be sure an overflow has happened by now due to instruction latency, */ - /* no more wait is needed and we only need to clear overflow flag */ - //wait_for_bit(); - TIFR0 = (1 << OCF0A); - /* Send data bits and calculate parity */ - for (uint8_t mask = 1; mask; mask <<= 1) { - // Check bit, transmit high or low bit accordingly and update parity bit - parity = (c & mask) ? (setup_bit_high(), ~parity) : (setup_bit_low(), parity); - wait_for_bit(); - } - /* Send parity bit */ - parity ? setup_bit_high() : setup_bit_low(); - wait_for_bit(); - /* Send stop bits */ - setup_bit_high(); - wait_for_bit(); - OCR0A = 2 * BIT_TIME - 1; // 2 bits - /* Ready for RX input, but high due to pull-up */ - DDR(UPDI_PORT) &= ~(1 << UPDI_PIN); - return c; -} - -/* Sends special sequences through the UPDI link */ -uint8_t UPDI_io::put(ctrl c) -{ - /* This nested function expects the timer output to just have gone low */ - /* It waits for 12 minimum baud bit times (break character) then goes high */ - auto break_pulse = [] { - TCCR0B = 4; // timer tick = 256/F_CPU seconds - OCR0A = F_CPU/125000; // bit time = F_CPU/125000 ticks ~ 2.048 ms - for (uint8_t i = 0; i < 11; i++) wait_for_bit(); // 12 bits ~ 24.6 ms, as recommended on the datasheet - setup_bit_high(); - wait_for_bit(); - DDR(UPDI_PORT) &= ~(1 << UPDI_PIN); - }; - - stop_timer(); - /* Send falling edge */ - OCR0A = BIT_TIME - 1; - TCNT0 = BIT_TIME - 2; - setup_bit_low(); - start_timer(); - /* Enable TX output */ - DDR(UPDI_PORT) |= (1 << UPDI_PIN); - /* clear overflow flag */ - TIFR0 = (1 << OCF0A); - switch (c) { - case double_break: - break_pulse(); - setup_bit_low(); - wait_for_bit(); - DDR(UPDI_PORT) |= (1 << UPDI_PIN); - case single_break: - break_pulse(); - wait_for_bit(); - break; - case enable: - /* - TCCR0A = 0; - DDRD |= (1 << DDD6); - PORTD &= ~(1 << DDD6); - __builtin_avr_nops(5); - PORTD |= (1 << DDD6); - DDRD &= ~(1 << DDD6); - setup_bit_high(); - break; - */ - default: - break; - } - OCR0A = BIT_TIME - 1; - TCNT0 = BIT_TIME - 2; - start_timer(); - return 0; -} - -uint8_t UPDI_io::get() { - stop_timer(); - /* Wait for middle of start bit */ - OCR0A = BIT_TIME / 2 - 1; - TCNT0 = 12; // overhead time; needs to be calibrated - /* Make sure overflow flag is reset */ - TIFR0 = (1 << OCF0A); - - /* Must disable pull-up, because the UPDI UART just sends very short output pulses at the beginning of each bit time. */ - /* If pull up is enabled, there will be a drift to high state that results in erroneous input sampling. */ - /* As a side effect, random electrical fluctuations of the input prevent an infinite wait loop */ - /* in case no target is connected. */ - PORT(UPDI_PORT) &= ~(1 << UPDI_PIN); - /* Wait for start bit */ - loop_until_bit_is_clear(PIN(UPDI_PORT), UPDI_PIN); - - start_timer(); - wait_for_bit(); - /* Setup sampling time */ - OCR0A = BIT_TIME - 1; -# ifdef _DEBUG - /* Timing pulse */ - PIND |= (1 << PIND7); - PIND |= (1 << PIND7); -# endif // _DEBUG - /* Sample bits */ - uint8_t c = 0; - //for (uint8_t i = 0; i < 8; i++) { - for (uint8_t mask = 1; mask; mask <<= 1) { - wait_for_bit(); - /* Take sample */ - //c /= 2; - if ( PIN(UPDI_PORT) & (1 << UPDI_PIN) ) { - //c |= 0x80; - c |= mask; - } -# ifdef _DEBUG - /* Timing pulse */ - PIND |= (1 << PIND7); - PIND |= (1 << PIND7); -# endif // _DEBUG - } - /* To Do Sample Parity */ - wait_for_bit(); -# ifdef _DEBUG - /* Timing pulse */ - PIND |= (1 << PIND7); - PIND |= (1 << PIND7); -# endif // _DEBUG - OCR0A = 2 * BIT_TIME + BIT_TIME / 2 - 1; // 2.5 bits - /* Return as soon as high parity or stop bits start */ - loop_until_bit_is_set(PIN(UPDI_PORT), UPDI_PIN); - /* Re-enable pull up */ - PORT(UPDI_PORT) |= (1 << UPDI_PIN); - return c; -} - -void UPDI_io::init(void) -{ -# ifdef _DEBUG - /* For RX timing measurement and debugging, make PD7 output */ - DDRD |= (1 << DDD7); -# endif // _DEBUG - setup_bit_high(); - /* initialize counter to near terminal count */ - TCNT0 = BIT_TIME - 2; - /* initialize OCR0A to 200k counts per second */ - OCR0A = BIT_TIME - 1; - start_timer(); -} - -namespace { - inline void setup_bit_low() { - /* OC0A will go low on match with OCR0A */ - /* Also, set CTC mode - reset timer on match with OCR0A */ - TCCR0A = (1 << COM0A1) | (0 << COM0A0) | (1 << WGM01); - } - - inline void setup_bit_high() { - /* OC0A will go high on match with OCR0A */ - /* Also, set CTC mode - reset timer on match with OCR0A */ - TCCR0A = (1 << COM0A1) | (1 << COM0A0) | (1 << WGM01); - } - - inline void wait_for_bit() { - /* Wait for compare match */ - loop_until_bit_is_set(TIFR0, OCF0A); - TIFR0 = (1 << OCF0A); - } - - inline void stop_timer() { - TCCR0B = 0; - } - - inline void start_timer() { - TCCR0B = 1; - } -} - - -#endif //UPDI_IO_TYPE == 1 From f8a30af8ef7f51f54a9cb0c2c408de3c6d34f3ed Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 18 Feb 2020 09:23:38 +0100 Subject: [PATCH 12/14] Delete updi_io_uart.cpp messed up commit: wrong directory --- updi_io_uart.cpp | 73 ------------------------------------------------ 1 file changed, 73 deletions(-) delete mode 100644 updi_io_uart.cpp diff --git a/updi_io_uart.cpp b/updi_io_uart.cpp deleted file mode 100644 index 91a722b..0000000 --- a/updi_io_uart.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * updi_io_uart.cpp - * - * Created: 01-02-2020 10:36:54 - * Author: cherry pick from AvrMega_MuxTO - */ - - - -// Includes -#include -#include "updi_io.h" -#include "sys.h" - - -#if UPDI_IO_TYPE == 3 -#include - -// Functions -/* Sends regular characters through the UPDI link */ -uint8_t UPDI_io::put(char c) { - HW_SERIAL.write(c); - HW_SERIAL.flush(); - //delayMicroseconds(10); - long start = millis(); - while (!HW_SERIAL.available() && millis() - start < 20) {} - char d = HW_SERIAL.read(); - if (c != d) { - // Serial.println("echo failed! " + String(d, HEX)); - } - return c; -} - -/* Sends special sequences through the UPDI link */ -uint8_t UPDI_io::put(ctrl c) -{ - HW_SERIAL.begin(300, SERIAL_8N1); - switch (c) { - case double_break: - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - break; - case single_break: - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - break; - default: - break; - } - delay(15); - while (HW_SERIAL.available()) { - HW_SERIAL.read(); - } - HW_SERIAL.begin(230400, SERIAL_8E2); - return 0; -} - -uint8_t UPDI_io::get() { - uint8_t c; - while (!HW_SERIAL.available()) {} - c = HW_SERIAL.read(); - //delayMicroseconds(5); - //Serial.println("get! " + String(c, HEX)); - return c; -} - -void UPDI_io::init(void) -{ - HW_SERIAL.begin(230400, SERIAL_8E2); -} -#endif //UPDI_IO_TYPE == 3 From 311b9bc073828bd68a872f2bb44b1923bab2ee33 Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 18 Feb 2020 09:23:53 +0100 Subject: [PATCH 13/14] Delete updi_io_uart.h messed up commit: wrong directory --- updi_io_uart.h | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 updi_io_uart.h diff --git a/updi_io_uart.h b/updi_io_uart.h deleted file mode 100644 index d72b85e..0000000 --- a/updi_io_uart.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * updi_io.h - * - * Created: 18-11-2017 10:38:31 - * Author: JMR_2 - */ - - -#ifndef UPDI_IO_H_ -#define UPDI_IO_H_ - -#include - -namespace UPDI_io { - // Enums - enum ctrl {single_break, double_break, enable}; - - // Function prototypes - uint8_t put(char) __attribute__((optimize("no-tree-loop-optimize"))); - uint8_t put(ctrl); - uint8_t get() __attribute__((optimize("no-tree-loop-optimize"))); - void init(void); -} - -#endif /* UPDI_IO_H_ */ \ No newline at end of file From 76490a0190a93a0392a3f2b37d09cf45a5f4e486 Mon Sep 17 00:00:00 2001 From: haweiler <32774925+haweiler@users.noreply.github.com> Date: Tue, 18 Feb 2020 10:24:19 +0100 Subject: [PATCH 14/14] Add support for 32U4 Added support for AVR 32U4. Due to an issue how COM (with 32U4) is handled in windows, not allowing the Arduino to send feedback while trying to program, it's only working using Linux. Arduino libraries are being used for init of USB and also for some LED flashing added for finding where the sketch stops working using windows. --- source/JICE_io.cpp | 237 ++++++------- source/JTAG2.cpp | 735 ++++++++++++++++++++-------------------- source/jtag2updi.cpp | 241 ++++++------- source/sys.cpp | 192 ++++++----- source/sys.h | 414 +++++++++++----------- source/updi_io_uart.cpp | 146 ++++---- 6 files changed, 1001 insertions(+), 964 deletions(-) diff --git a/source/JICE_io.cpp b/source/JICE_io.cpp index 991148a..76f709d 100644 --- a/source/JICE_io.cpp +++ b/source/JICE_io.cpp @@ -1,118 +1,119 @@ -/* - * stk_io.cpp - * - * Created: 18-11-2017 15:20:29 - * Author: JMR_2 - */ - -// Includes -#include -#include -#include "JICE_io.h" -#include "sys.h" - -namespace { - // *** Baud rate lookup table for UBRR0 register *** - // Indexed by valid values for PARAM_BAUD_RATE_VAL (defined in JTAG2.h) - FLASH baud_tbl[8] = {baud_reg_val(2400), baud_reg_val(4800), baud_reg_val(9600), baud_reg_val(19200), baud_reg_val(38400), baud_reg_val(57600), baud_reg_val(115200), baud_reg_val(14400)}; -} - -// Functions -uint8_t JICE_io::put(char c) { -#ifdef __AVR_ATmega16__ - loop_until_bit_is_set(UCSRA, UDRE); - return UDR = c; -#elif defined XTINY - loop_until_bit_is_set(HOST_USART.STATUS, USART_DREIF_bp); - return HOST_USART.TXDATAL = c; -#elif defined __AVR_ATmega32U4__ - // wait for Serial to be active - while (!SERIALCOM){ SYS::LED_blink(2, 1, 100);}; - SERIALCOM.write(c); //test 32U4 - return c; //test 32U4 -#else - loop_until_bit_is_set(UCSR0A, UDRE0); - return UDR0 = c; -#endif -} - -uint8_t JICE_io::get(void) { -#ifdef __AVR_ATmega16__ - loop_until_bit_is_set(UCSRA, RXC); /* Wait until data exists. */ - return UDR; -#elif defined XTINY - loop_until_bit_is_set(HOST_USART.STATUS, USART_RXCIF_bp); /* Wait until data exists. */ - return HOST_USART.RXDATAL; -#elif defined __AVR_ATmega32U4__ - //while (!Serial.available()); //test 32U4 - uint8_t c = SERIALCOM.read(); //test 32U4 - return c; //test 32U4 -#else - loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ - return UDR0; -#endif -} - -void JICE_io::init(void) { -#ifdef __AVR_ATmega16__ - /* Set double speed */ - UCSRA = (1< +#include +#include "JICE_io.h" +#include "sys.h" + +namespace { + // *** Baud rate lookup table for UBRR0 register *** + // Indexed by valid values for PARAM_BAUD_RATE_VAL (defined in JTAG2.h) + FLASH baud_tbl[8] = {baud_reg_val(2400), baud_reg_val(4800), baud_reg_val(9600), baud_reg_val(19200), baud_reg_val(38400), baud_reg_val(57600), baud_reg_val(115200), baud_reg_val(14400)}; +} + +// Functions +uint8_t JICE_io::put(char c) { +#ifdef __AVR_ATmega16__ + loop_until_bit_is_set(UCSRA, UDRE); + return UDR = c; +#elif defined XTINY + loop_until_bit_is_set(HOST_USART.STATUS, USART_DREIF_bp); + return HOST_USART.TXDATAL = c; +#elif defined __AVR_ATmega32U4__ + // wait for Serial to be active + // while (!SERIALCOM); + // commented out: timeout/error communicating with programmer (status -1) + SERIALCOM.write(c); + return c; +#else + loop_until_bit_is_set(UCSR0A, UDRE0); + return UDR0 = c; +#endif +} + +uint8_t JICE_io::get(void) { +#ifdef __AVR_ATmega16__ + loop_until_bit_is_set(UCSRA, RXC); /* Wait until data exists. */ + return UDR; +#elif defined XTINY + loop_until_bit_is_set(HOST_USART.STATUS, USART_RXCIF_bp); /* Wait until data exists. */ + return HOST_USART.RXDATAL; +#elif defined __AVR_ATmega32U4__ + uint8_t c = SERIALCOM.read(); + return c; +#else + loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ + return UDR0; +#endif +} + +void JICE_io::init(void) { +#ifdef __AVR_ATmega16__ + /* Set double speed */ + UCSRA = (1< sizeof(packet.body)) return false; - if (JICE_io::get() != TOKEN) return false; - crc = CRC::next(TOKEN, crc); - for (uint16_t i = 0; i < packet.size_word[0]; i++) { - crc = CRC::next(packet.body[i] = JICE_io::get(), crc); - } - if ((uint16_t)(JICE_io::get() | (JICE_io::get() << 8)) != crc) return false; - return true; - } - - void JTAG2::answer() { - uint16_t crc = CRC::next(JICE_io::put(MESSAGE_START)); - for (uint16_t i = 0; i < 6; i++) { - crc = CRC::next(JICE_io::put(packet.raw[i]), crc); - } - crc = CRC::next(JICE_io::put(TOKEN), crc); - for (uint16_t i = 0; i < packet.size_word[0]; i++) { - crc = CRC::next(JICE_io::put(packet.body[i]), crc); - } - JICE_io::put(crc); - JICE_io::put(crc >> 8); - } - - void JTAG2::delay_exec() { - // wait for transmission complete - JICE_io::flush(); - // set baud rate - JICE_io::set_baud(PARAM_BAUD_RATE_VAL); - } - -// *** Set status function *** - void JTAG2::set_status(uint8_t status_code){ - packet.size_word[0] = 1; - packet.body[0] = status_code; - } - -// *** General command functions *** - // *** Signature response message *** - FLASH JTAG2::sgn_resp[29] { 0x86, 1, - 1, PARAM_FW_VER_M_MIN_VAL, PARAM_FW_VER_M_MAJ_VAL, PARAM_HW_VER_M_VAL, - 1, PARAM_FW_VER_S_MIN_VAL, PARAM_FW_VER_S_MAJ_VAL, PARAM_HW_VER_S_VAL, - 0, 0, 0, 0, 0, 0, - 'J', 'T', 'A', 'G', 'I', 'C', 'E', ' ', 'm', 'k', 'I', 'I', 0}; - void JTAG2::sign_on(){ - // Initialize JTAGICE2 variables - JTAG2::PARAM_EMU_MODE_VAL = 0x02; - JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; - /* Initialize or enable UPDI */ - UPDI_io::put(UPDI_io::double_break); - UPDI::stcs(UPDI::reg::Control_A, 6); - // Send sign on message - packet.size_word[0] = sizeof(sgn_resp); - for (uint8_t i = 0; i < sizeof(sgn_resp); i++) { - packet.body[i] = sgn_resp[i]; - } - } - - void JTAG2::get_parameter(){ - uint8_t & status = packet.body[0]; - uint8_t & parameter = packet.body[1]; - switch (parameter) { - case PARAM_HW_VER: - packet.size_word[0] = 3; - packet.body[1] = PARAM_HW_VER_M_VAL; - packet.body[2] = PARAM_HW_VER_S_VAL; - break; - case PARAM_FW_VER: - packet.size_word[0] = 5; - packet.body[1] = PARAM_FW_VER_M_MIN_VAL; - packet.body[2] = PARAM_FW_VER_M_MAJ_VAL; - packet.body[3] = PARAM_FW_VER_S_MIN_VAL; - packet.body[4] = PARAM_FW_VER_S_MAJ_VAL; - break; - case PARAM_EMU_MODE: - packet.size_word[0] = 2; - packet.body[1] = PARAM_EMU_MODE_VAL; - break; - case PARAM_BAUD_RATE: - packet.size_word[0] = 2; - packet.body[1] = PARAM_BAUD_RATE_VAL; - break; - case PARAM_VTARGET: - packet.size_word[0] = 3; - packet.body[1] = PARAM_VTARGET_VAL & 0xFF; - packet.body[2] = PARAM_VTARGET_VAL >> 8; - break; - default: - set_status(RSP_ILLEGAL_PARAMETER); - return; - } - status = RSP_PARAMETER; - return; - } - - void JTAG2::set_parameter(){ - uint8_t & parameter = packet.body[1]; - switch (parameter) { - case PARAM_EMU_MODE: - PARAM_EMU_MODE_VAL = packet.body[2]; - break; - case PARAM_BAUD_RATE: - PARAM_BAUD_RATE_VAL = (baud_rate)packet.body[2]; - break; - default: - set_status(RSP_ILLEGAL_PARAMETER); - return; - } - set_status(RSP_OK); - } - - void JTAG2::set_device_descriptor(){ - flash_pagesize = packet.body[244]; - eeprom_pagesize = packet.body[246]; - set_status(RSP_OK); - } - -// *** Target mode set functions *** - // *** Sets MCU in program mode, if possibe *** - void JTAG2::enter_progmode(){ - // Reset the MCU now, to prevent the WDT (if active) to reset it at an unpredictable moment - UPDI::CPU_reset(); - // Now we have time to enter program mode (this mode also disables the WDT) - const uint8_t system_status = UPDI::CPU_mode<0xEF>(); - switch (system_status){ - // in normal operation mode - case 0x82: - // Write NVN unlock key (allows read access to all addressing space) - UPDI::write_key(UPDI::NVM_Prog); - // Request reset - UPDI::CPU_reset(); - // Wait for NVM unlock state - //while (UPDI::CPU_mode() != 0x08); - // already in program mode - case 0x08: - // better clear the page buffer, just in case. - UPDI::sts_b(NVM::NVM_base | NVM::CTRLA, NVM::PBC); - // Turn on LED to indicate program mode - SYS::setLED(); - set_status(RSP_OK); - break; - // in other modes fail and inform host of wrong mode - default: - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = system_status; // 0x01; - } - } - - // *** Sets MCU in normal runnning mode, if possibe *** - void JTAG2::leave_progmode(){ - const uint8_t system_status = UPDI::CPU_mode<0xEF>(); - switch (system_status){ - // in program mode - case 0x08: - // Request reset - UPDI::CPU_reset(); - // Wait for normal mode - // while (UPDI::CPU_mode<0xEF>() != 0x82); - // already in normal mode - case 0x82: - // Turn off LED to indicate normal mode - SYS::clearLED(); - set_status(RSP_OK); - break; - // in other modes fail and inform host of wrong mode - default: - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = system_status; // 0x01; - } - } - -// *** Read/Write/Erase functions *** - - void JTAG2::read_mem() { - if (UPDI::CPU_mode() != 0x08){ - // fail if not in program mode - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = 0x01; - } - else { - // in program mode - const uint16_t NumBytes = (packet.body[3] << 8) | packet.body[2]; - // Get physical address for reading - const uint16_t address = (packet.body[7] << 8) | packet.body[6]; - // Set UPDI pointer to address - UPDI::stptr_w(address); - // Read block - UPDI::rep(NumBytes - 1); - packet.body[1] = UPDI::ldinc_b(); - for (uint16_t i = 2; i <= NumBytes; i++) { - packet.body[i] = UPDI_io::get(); - } - packet.size_word[0] = NumBytes + 1; - packet.body[0] = RSP_MEMORY; - } - } - - void JTAG2::write_mem() { - if (UPDI::CPU_mode() != 0x08){ - // fail if not in program mode - packet.size_word[0] = 2; - packet.body[0] = RSP_ILLEGAL_MCU_STATE; - packet.body[1] = 0x01; - } - else { - // in program mode - const uint8_t mem_type = packet.body[1]; - const uint16_t address = packet.body[6] | (packet.body[7] << 8); - const uint16_t lenght = packet.body[2] | (packet.body[3] << 8); /* number of bytes to write */ - const bool is_flash = ((mem_type == MTYPE_FLASH) || (mem_type == MTYPE_BOOT_FLASH)); - const uint8_t buff_size = is_flash ? flash_pagesize : eeprom_pagesize; - const uint8_t write_cmnd = is_flash ? NVM::WP : NVM::ERWP; - switch (mem_type) { - case MTYPE_FUSE_BITS: - case MTYPE_LOCK_BITS: - NVM_fuse_write (address, packet.body[10]); - break; - case MTYPE_FLASH: - case MTYPE_BOOT_FLASH: - case MTYPE_EEPROM_XMEGA: - case MTYPE_USERSIG: - NVM_buffered_write(address, lenght, buff_size, write_cmnd); - break; - default: - set_status(RSP_ILLEGAL_MEMORY_TYPE); - return; - } - set_status(RSP_OK); - } - } - - void JTAG2::erase() { - const uint8_t erase_type = packet.body[1]; - const uint16_t address = packet.body[2] | (packet.body[3] << 8); - switch (erase_type) { - case 0: - // Write Chip Erase key - UPDI::write_key(UPDI::Chip_Erase); - // Request reset - UPDI::CPU_reset(); - // Erase chip process exits program mode, reenter... - enter_progmode(); - break; - case 4: - case 5: - NVM::wait(); - UPDI::sts_b(address, 0xFF); - NVM::command(NVM::ER); - set_status(RSP_OK); - break; - case 6: - case 7: - break; - default: - set_status(RSP_FAILED); - } - } - -// *** Local functions definition *** -namespace { - void NVM_fuse_write (uint16_t address, uint8_t data) { - // Setup UPDI pointer - UPDI::stptr_w(NVM::NVM_base + NVM::DATA_lo); - // Send data to the NVM controller - UPDI::stinc_b(data); - UPDI::stinc_b(0x00); - // Send address to the NVM controller - UPDI::stinc_b(address & 0xFF); - UPDI::stinc_b(address >> 8); - // Execute fuse write - NVM::command(NVM::WFU); - } - - void NVM_buffered_write(const uint16_t address, const uint16_t length, const uint8_t buff_size, const uint8_t write_cmnd) { - uint8_t current_byte_index = 10; /* Index of the first byte to send inside the JTAG2 command body */ - uint16_t bytes_remaining = length; /* number of bytes to write */ - - // Sends a block of bytes from the command body to memory, using the UPDI interface - // On entry, the UPDI pointer must already point to the desired address - // On exit, the UPDI pointer points to the next byte after the last one written - // Returns updated index into the command body, pointing to the first unsent byte. - auto updi_send_block = [] (uint8_t count, uint8_t index) { - count--; - NVM::wait(); - UPDI::rep(count); - UPDI::stinc_b(JTAG2::packet.body[index]); - for (uint8_t i = count; i; i--) { - UPDI_io::put(JTAG2::packet.body[++index]); - UPDI_io::get(); - } - return ++index; - }; - - // Setup UPDI pointer for block transfer - UPDI::stptr_w(address); - /* Check address alignment, calculate number of unaligned bytes to send */ - uint8_t unaligned_bytes = (-address & (buff_size - 1)); - if (unaligned_bytes > bytes_remaining) unaligned_bytes = bytes_remaining; - /* If there are unaligned bytes, they must be sent first */ - if (unaligned_bytes) { - // Send unaligned block - current_byte_index = updi_send_block(unaligned_bytes, current_byte_index); - bytes_remaining -= unaligned_bytes; - NVM::command(write_cmnd); - } - while (bytes_remaining) { - /* Send a buff_size amount of bytes */ - if (bytes_remaining >= buff_size) { - current_byte_index = updi_send_block(buff_size, current_byte_index); - bytes_remaining -= buff_size; - } - /* Send a NumBytes amount of bytes */ - else { - current_byte_index = updi_send_block(bytes_remaining, current_byte_index); - bytes_remaining = 0; - } - NVM::command(write_cmnd); - } - } -} +/* + * STK500.cpp + * + * Created: 08-12-2017 19:47:27 + * Author: JMR_2 + */ + +#include "JTAG2.h" +#include "JICE_io.h" +#include "NVM.h" +#include "crc16.h" +#include "UPDI_hi_lvl.h" + +// *** Writeable Parameter Values *** +uint8_t JTAG2::PARAM_EMU_MODE_VAL; +JTAG2::baud_rate JTAG2::PARAM_BAUD_RATE_VAL; + +// *** STK500 packet *** +JTAG2::packet_t JTAG2::packet; + +namespace { + // *** Private variables *** + uint8_t flash_pagesize; + uint8_t eeprom_pagesize; + + // *** Local functions declaration *** + void NVM_fuse_write (uint16_t address, uint8_t data); + void NVM_buffered_write(uint16_t address, uint16_t lenght, uint8_t buff_size, uint8_t write_type); +} + +// *** Packet functions *** + bool JTAG2::receive() { + while (JICE_io::get() != MESSAGE_START); + uint16_t crc = CRC::next(MESSAGE_START); + for (uint16_t i = 0; i < 6; i++) { + crc = CRC::next(packet.raw[i] = JICE_io::get(), crc); + } + if (packet.size_word[0] > sizeof(packet.body)) return false; + if (JICE_io::get() != TOKEN) return false; + crc = CRC::next(TOKEN, crc); + for (uint16_t i = 0; i < packet.size_word[0]; i++) { + crc = CRC::next(packet.body[i] = JICE_io::get(), crc); + } + if ((uint16_t)(JICE_io::get() | (JICE_io::get() << 8)) != crc) return false; + return true; + } + + void JTAG2::answer() { + uint16_t crc = CRC::next(JICE_io::put(MESSAGE_START)); + for (uint16_t i = 0; i < 6; i++) { + crc = CRC::next(JICE_io::put(packet.raw[i]), crc); + } + crc = CRC::next(JICE_io::put(TOKEN), crc); + for (uint16_t i = 0; i < packet.size_word[0]; i++) { + crc = CRC::next(JICE_io::put(packet.body[i]), crc); + } + JICE_io::put(crc); + JICE_io::put(crc >> 8); + } + + void JTAG2::delay_exec() { + // wait for transmission complete + JICE_io::flush(); + // set baud rate + JICE_io::set_baud(PARAM_BAUD_RATE_VAL); + } + +// *** Set status function *** + void JTAG2::set_status(uint8_t status_code){ + packet.size_word[0] = 1; + packet.body[0] = status_code; + } + +// *** General command functions *** + // *** Signature response message *** + FLASH JTAG2::sgn_resp[29] { 0x86, 1, + 1, PARAM_FW_VER_M_MIN_VAL, PARAM_FW_VER_M_MAJ_VAL, PARAM_HW_VER_M_VAL, + 1, PARAM_FW_VER_S_MIN_VAL, PARAM_FW_VER_S_MAJ_VAL, PARAM_HW_VER_S_VAL, + 0, 0, 0, 0, 0, 0, + 'J', 'T', 'A', 'G', 'I', 'C', 'E', ' ', 'm', 'k', 'I', 'I', 0}; + void JTAG2::sign_on(){ + // Initialize JTAGICE2 variables + JTAG2::PARAM_EMU_MODE_VAL = 0x02; + JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; + /* Initialize or enable UPDI */ + UPDI_io::put(UPDI_io::double_break); +#if UPDI_IO_TYPE == 3 + // use timing from MEGA_AVR project, but worked with timing from bitbang as well + + // Timing Type3 - UPDI UART + // Bit 3 - Collision and Contention Detection Disable + UPDI::stcs(UPDI::reg::Control_B, 8); + // Bit 7 – IBDLY Inter-Byte Delay Enable + // Bit 5=0 Parity enable + // Bit 4=0 Time-out detection enable + // Bit 3=0 RSD Response Signature Enable + // Bit 2:0 0x0 UPDI Guard Time: 128 cycles (default) + UPDI::stcs(UPDI::reg::Control_A, 0x80); + //UPDI::stcs(UPDI::reg::Control_A, 6); +#else + // Timing Type1 UPDI bitbang + // UPDI Guard Time: 2 cycles + UPDI::stcs(UPDI::reg::Control_A, 6); +#endif + // Send sign on message + packet.size_word[0] = sizeof(sgn_resp); + for (uint8_t i = 0; i < sizeof(sgn_resp); i++) { + packet.body[i] = sgn_resp[i]; + } + } + + void JTAG2::get_parameter(){ + uint8_t & status = packet.body[0]; + uint8_t & parameter = packet.body[1]; + switch (parameter) { + case PARAM_HW_VER: + packet.size_word[0] = 3; + packet.body[1] = PARAM_HW_VER_M_VAL; + packet.body[2] = PARAM_HW_VER_S_VAL; + break; + case PARAM_FW_VER: + packet.size_word[0] = 5; + packet.body[1] = PARAM_FW_VER_M_MIN_VAL; + packet.body[2] = PARAM_FW_VER_M_MAJ_VAL; + packet.body[3] = PARAM_FW_VER_S_MIN_VAL; + packet.body[4] = PARAM_FW_VER_S_MAJ_VAL; + break; + case PARAM_EMU_MODE: + packet.size_word[0] = 2; + packet.body[1] = PARAM_EMU_MODE_VAL; + break; + case PARAM_BAUD_RATE: + packet.size_word[0] = 2; + packet.body[1] = PARAM_BAUD_RATE_VAL; + break; + case PARAM_VTARGET: + packet.size_word[0] = 3; + packet.body[1] = PARAM_VTARGET_VAL & 0xFF; + packet.body[2] = PARAM_VTARGET_VAL >> 8; + break; + default: + set_status(RSP_ILLEGAL_PARAMETER); + return; + } + status = RSP_PARAMETER; + return; + } + + void JTAG2::set_parameter(){ + uint8_t & parameter = packet.body[1]; + switch (parameter) { + case PARAM_EMU_MODE: + PARAM_EMU_MODE_VAL = packet.body[2]; + break; + case PARAM_BAUD_RATE: + PARAM_BAUD_RATE_VAL = (baud_rate)packet.body[2]; + break; + default: + set_status(RSP_ILLEGAL_PARAMETER); + return; + } + set_status(RSP_OK); + } + + void JTAG2::set_device_descriptor(){ + flash_pagesize = packet.body[244]; + eeprom_pagesize = packet.body[246]; + set_status(RSP_OK); + } + +// *** Target mode set functions *** + // *** Sets MCU in program mode, if possibe *** + void JTAG2::enter_progmode(){ + // Reset the MCU now, to prevent the WDT (if active) to reset it at an unpredictable moment + UPDI::CPU_reset(); + // Now we have time to enter program mode (this mode also disables the WDT) + const uint8_t system_status = UPDI::CPU_mode<0xEF>(); + switch (system_status){ + // in normal operation mode + case 0x82: + // Write NVN unlock key (allows read access to all addressing space) + UPDI::write_key(UPDI::NVM_Prog); + // Request reset + UPDI::CPU_reset(); + // Wait for NVM unlock state + //while (UPDI::CPU_mode() != 0x08); + // already in program mode + case 0x08: + // better clear the page buffer, just in case. + UPDI::sts_b(NVM::NVM_base | NVM::CTRLA, NVM::PBC); + // Turn on LED to indicate program mode + SYS::setLED(); + set_status(RSP_OK); + break; + // in other modes fail and inform host of wrong mode + default: + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = system_status; // 0x01; + } + } + + // *** Sets MCU in normal runnning mode, if possibe *** + void JTAG2::leave_progmode(){ + const uint8_t system_status = UPDI::CPU_mode<0xEF>(); + switch (system_status){ + // in program mode + case 0x08: + // Request reset + UPDI::CPU_reset(); + // Wait for normal mode + // while (UPDI::CPU_mode<0xEF>() != 0x82); + // already in normal mode + case 0x82: + // Turn off LED to indicate normal mode + SYS::clearLED(); + set_status(RSP_OK); + break; + // in other modes fail and inform host of wrong mode + default: + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = system_status; // 0x01; + } + } + +// *** Read/Write/Erase functions *** + + void JTAG2::read_mem() { + if (UPDI::CPU_mode() != 0x08){ + // fail if not in program mode + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = 0x01; + } + else { + // in program mode + const uint16_t NumBytes = (packet.body[3] << 8) | packet.body[2]; + // Get physical address for reading + const uint16_t address = (packet.body[7] << 8) | packet.body[6]; + // Set UPDI pointer to address + UPDI::stptr_w(address); + // Read block + UPDI::rep(NumBytes - 1); + packet.body[1] = UPDI::ldinc_b(); + for (uint16_t i = 2; i <= NumBytes; i++) { + packet.body[i] = UPDI_io::get(); + } + packet.size_word[0] = NumBytes + 1; + packet.body[0] = RSP_MEMORY; + } + } + + void JTAG2::write_mem() { + if (UPDI::CPU_mode() != 0x08){ + // fail if not in program mode + packet.size_word[0] = 2; + packet.body[0] = RSP_ILLEGAL_MCU_STATE; + packet.body[1] = 0x01; + } + else { + // in program mode + const uint8_t mem_type = packet.body[1]; + const uint16_t address = packet.body[6] | (packet.body[7] << 8); + const uint16_t lenght = packet.body[2] | (packet.body[3] << 8); /* number of bytes to write */ + const bool is_flash = ((mem_type == MTYPE_FLASH) || (mem_type == MTYPE_BOOT_FLASH)); + const uint8_t buff_size = is_flash ? flash_pagesize : eeprom_pagesize; + const uint8_t write_cmnd = is_flash ? NVM::WP : NVM::ERWP; + switch (mem_type) { + case MTYPE_FUSE_BITS: + case MTYPE_LOCK_BITS: + NVM_fuse_write (address, packet.body[10]); + break; + case MTYPE_FLASH: + case MTYPE_BOOT_FLASH: + case MTYPE_EEPROM_XMEGA: + case MTYPE_USERSIG: + NVM_buffered_write(address, lenght, buff_size, write_cmnd); + break; + default: + set_status(RSP_ILLEGAL_MEMORY_TYPE); + return; + } + set_status(RSP_OK); + } + } + + void JTAG2::erase() { + const uint8_t erase_type = packet.body[1]; + const uint16_t address = packet.body[2] | (packet.body[3] << 8); + switch (erase_type) { + case 0: + // Write Chip Erase key + UPDI::write_key(UPDI::Chip_Erase); + // Request reset + UPDI::CPU_reset(); + // Erase chip process exits program mode, reenter... + enter_progmode(); + break; + case 4: + case 5: + NVM::wait(); + UPDI::sts_b(address, 0xFF); + NVM::command(NVM::ER); + set_status(RSP_OK); + break; + case 6: + case 7: + break; + default: + set_status(RSP_FAILED); + } + } + +// *** Local functions definition *** +namespace { + void NVM_fuse_write (uint16_t address, uint8_t data) { + // Setup UPDI pointer + UPDI::stptr_w(NVM::NVM_base + NVM::DATA_lo); + // Send data to the NVM controller + UPDI::stinc_b(data); + UPDI::stinc_b(0x00); + // Send address to the NVM controller + UPDI::stinc_b(address & 0xFF); + UPDI::stinc_b(address >> 8); + // Execute fuse write + NVM::command(NVM::WFU); + } + + void NVM_buffered_write(const uint16_t address, const uint16_t length, const uint8_t buff_size, const uint8_t write_cmnd) { + uint8_t current_byte_index = 10; /* Index of the first byte to send inside the JTAG2 command body */ + uint16_t bytes_remaining = length; /* number of bytes to write */ + + // Sends a block of bytes from the command body to memory, using the UPDI interface + // On entry, the UPDI pointer must already point to the desired address + // On exit, the UPDI pointer points to the next byte after the last one written + // Returns updated index into the command body, pointing to the first unsent byte. + auto updi_send_block = [] (uint8_t count, uint8_t index) { + count--; + NVM::wait(); + UPDI::rep(count); + UPDI::stinc_b(JTAG2::packet.body[index]); + for (uint8_t i = count; i; i--) { + UPDI_io::put(JTAG2::packet.body[++index]); + UPDI_io::get(); + } + return ++index; + }; + + // Setup UPDI pointer for block transfer + UPDI::stptr_w(address); + /* Check address alignment, calculate number of unaligned bytes to send */ + uint8_t unaligned_bytes = (-address & (buff_size - 1)); + if (unaligned_bytes > bytes_remaining) unaligned_bytes = bytes_remaining; + /* If there are unaligned bytes, they must be sent first */ + if (unaligned_bytes) { + // Send unaligned block + current_byte_index = updi_send_block(unaligned_bytes, current_byte_index); + bytes_remaining -= unaligned_bytes; + NVM::command(write_cmnd); + } + while (bytes_remaining) { + /* Send a buff_size amount of bytes */ + if (bytes_remaining >= buff_size) { + current_byte_index = updi_send_block(buff_size, current_byte_index); + bytes_remaining -= buff_size; + } + /* Send a NumBytes amount of bytes */ + else { + current_byte_index = updi_send_block(bytes_remaining, current_byte_index); + bytes_remaining = 0; + } + NVM::command(write_cmnd); + } + } +} diff --git a/source/jtag2updi.cpp b/source/jtag2updi.cpp index 4347e97..4caea0a 100644 --- a/source/jtag2updi.cpp +++ b/source/jtag2updi.cpp @@ -1,120 +1,121 @@ -/* - * j2updi.cpp - * - * Created: 11-11-2017 22:29:58 - * Author : JMR_2 - */ - -// Includes -#if defined __AVR_ATmega32U4__ - #include - #include "USBAPI.h" - -// Declared weak in Arduino.h to allow user redefinitions. - int atexit(void (* /*func*/ )()) { return 0; } - -// Weak empty variant initialization function. -// May be redefined by variant files. - void initVariant() __attribute__((weak)); - void initVariant() { } - - void setupUSB() __attribute__((weak)); - void setupUSB() { } - -#endif - -#include "sys.h" -#if UPDI_IO_TYPE==3 - #include "updi_io_uart.h" -#else - #include "updi_io.h" -#endif -#include "JICE_io.h" -#include "JTAG2.h" - -/* Internal stuff */ -namespace { - // Prototypes - void setup2(); - void loop2(); -} - -int main(void) -{ - #if defined __AVR_ATmega32U4__ - init(); - initVariant(); - #endif - - #if defined(USBCON) - USBDevice.attach(); - #endif - setup2(); - loop2(); -} - -/* Internal stuff */ -namespace { - inline void setup2() { - /* Initialize MCU */ - SYS::init(); - - /* Initialize serial links */ - JICE_io::init(); - UPDI_io::init(); - } - - - inline void loop2() { - while (1) { - - // Receive command - while(!JTAG2::receive()); - // Process command - switch (JTAG2::packet.body[0]) { - case JTAG2::CMND_GET_SIGN_ON: - JTAG2::sign_on(); - break; - case JTAG2::CMND_GET_PARAMETER: - JTAG2::get_parameter(); - break; - case JTAG2::CMND_SET_PARAMETER: - JTAG2::set_parameter(); - break; - case JTAG2::CMND_RESET: - case JTAG2::CMND_ENTER_PROGMODE: - JTAG2::enter_progmode(); - break; - case JTAG2::CMND_SIGN_OFF: - // Restore default baud rate before exiting - JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; - case JTAG2::CMND_LEAVE_PROGMODE: - JTAG2::leave_progmode(); - break; - case JTAG2::CMND_GET_SYNC: - case JTAG2::CMND_GO: - JTAG2::set_status(JTAG2::RSP_OK); - break; - case JTAG2::CMND_SET_DEVICE_DESCRIPTOR: - JTAG2::set_device_descriptor(); - break; - case JTAG2::CMND_READ_MEMORY: - JTAG2::read_mem(); - break; - case JTAG2::CMND_WRITE_MEMORY: - JTAG2::write_mem(); - break; - case JTAG2::CMND_XMEGA_ERASE: - JTAG2::erase(); - break; - default: - JTAG2::set_status(JTAG2::RSP_FAILED); - break; - } - // send response - JTAG2::answer(); - // some commands need to be executed after sending the answer - JTAG2::delay_exec(); - } - } -} +/* + * j2updi.cpp + * + * Created: 11-11-2017 22:29:58 + * Author : JMR_2 + */ + +// Includes +#if defined __AVR_ATmega32U4__ + #include + #include "USBAPI.h" + +// Declared weak in Arduino.h to allow user redefinitions. + int atexit(void (* /*func*/ )()) { return 0; } + +// Weak empty variant initialization function. +// May be redefined by variant files. + void initVariant() __attribute__((weak)); + void initVariant() { } + + void setupUSB() __attribute__((weak)); + void setupUSB() { } + +#endif + +#include "sys.h" +#if UPDI_IO_TYPE==3 + #include "updi_io_uart.h" +#else + #include "updi_io.h" +#endif +#include "JICE_io.h" +#include "JTAG2.h" + +/* Internal stuff */ +namespace { + // Prototypes + void setup2(); + void loop2(); +} + +int main(void) +{ + #if defined __AVR_ATmega32U4__ + init(); + initVariant(); + #endif + + #if defined(USBCON) + USBDevice.attach(); + #endif + setup2(); + loop2(); +} + +/* Internal stuff */ +namespace { + inline void setup2() { + /* Initialize MCU */ + SYS::init(); + + /* Initialize serial links */ + JICE_io::init(); + UPDI_io::init(); + } + + + inline void loop2() { + while (1) { + + // Receive command + while(!JTAG2::receive()); + // Process command + switch (JTAG2::packet.body[0]) { + case JTAG2::CMND_GET_SIGN_ON: + JTAG2::sign_on(); + break; + case JTAG2::CMND_GET_PARAMETER: + JTAG2::get_parameter(); + break; + case JTAG2::CMND_SET_PARAMETER: + JTAG2::set_parameter(); + break; + case JTAG2::CMND_RESET: + case JTAG2::CMND_ENTER_PROGMODE: + JTAG2::enter_progmode(); + break; + case JTAG2::CMND_SIGN_OFF: + // Restore default baud rate before exiting + JTAG2::PARAM_BAUD_RATE_VAL = JTAG2::baud_19200; + case JTAG2::CMND_LEAVE_PROGMODE: + JTAG2::leave_progmode(); + break; + case JTAG2::CMND_GET_SYNC: + case JTAG2::CMND_GO: + JTAG2::set_status(JTAG2::RSP_OK); + break; + case JTAG2::CMND_SET_DEVICE_DESCRIPTOR: + JTAG2::set_device_descriptor(); + break; + case JTAG2::CMND_READ_MEMORY: + JTAG2::read_mem(); + break; + case JTAG2::CMND_WRITE_MEMORY: + JTAG2::write_mem(); + break; + case JTAG2::CMND_XMEGA_ERASE: + JTAG2::erase(); + break; + default: + JTAG2::set_status(JTAG2::RSP_FAILED); + break; + } + // send response + //SYS::LED_blink(2, 5, 100); + JTAG2::answer(); + // some commands need to be executed after sending the answer + JTAG2::delay_exec(); + } + } +} diff --git a/source/sys.cpp b/source/sys.cpp index 67ed433..483b605 100644 --- a/source/sys.cpp +++ b/source/sys.cpp @@ -1,87 +1,105 @@ -/* - * sys.cpp - * - * Created: 02-10-2018 13:07:52 - * Author: JMR_2 - */ - -#include -#include -#include - -#include "sys.h" - -void SYS::init(void) { - -#ifndef __AVR_ATmega16__ -# if defined HW_SERIAL -// skip all init, UART used -# elif defined XTINY - // Set clock speed to maximum (default 20MHz, or 16MHz set by fuse) - _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); - /* Disable unused peripherals */ - //ToDo -# else -# if defined(ARDUINO_AVR_LARDU_328E) - clock_prescale_set ( (clock_div_t) __builtin_log2(32000000UL / F_CPU)); -# endif - /* Disable digital input buffers on port C */ - DIDR0 = 0x3F; - /* Disable unused peripherals */ - ACSR = 1 << ACD; // turn off comparator -# endif //HW_SERIAL, XTINY -# ifndef HW_SERIAL - /* Enable all UPDI port pull-ups */ - PORT(UPDI_PORT) = 0xFF; -# endif - /* Enable LED */ - //PORT(LED_PORT) |= (1 << LED_PIN); - /* Enable all LED port pull-ups, except for the LED pin */ - PORT(LED_PORT) = 0xFF - (1 << LED_PIN); -#else - /* No interrupts */ - sei(); - /* Enable all UPDI port pull-ups */ - PORT(UPDI_PORT) = 0xFF; - /* Enable LED */ - PORT(LED_PORT) |= (1 << LED_PIN); - /* Enable all LED port pull-ups, except for the LED pin */ - PORT(LED_PORT) = 0xFF - (1 << LED_PIN); - - - /* Disable unused peripherals */ - SPCR &= ~(1< +#include +#include + +#include "sys.h" + +void SYS::init(void) { + +#ifndef __AVR_ATmega16__ +# if defined HW_SERIAL +// skip all init, UART used +# elif defined XTINY + // Set clock speed to maximum (default 20MHz, or 16MHz set by fuse) + _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); + /* Disable unused peripherals */ + //ToDo +# else +# if defined(ARDUINO_AVR_LARDU_328E) + clock_prescale_set ( (clock_div_t) __builtin_log2(32000000UL / F_CPU)); +# endif + /* Disable digital input buffers on port C */ + DIDR0 = 0x3F; + /* Disable unused peripherals */ + ACSR = 1 << ACD; // turn off comparator +# endif //HW_SERIAL, XTINY +# ifndef HW_SERIAL + /* Enable all UPDI port pull-ups */ + PORT(UPDI_PORT) = 0xFF; +# endif + /* Enable LED */ + //PORT(LED_PORT) |= (1 << LED_PIN); + /* Enable all LED port pull-ups, except for the LED pin */ + PORT(LED_PORT) = 0xFF - (1 << LED_PIN); +#else + /* No interrupts */ + sei(); + /* Enable all UPDI port pull-ups */ + PORT(UPDI_PORT) = 0xFF; + /* Enable LED */ + PORT(LED_PORT) |= (1 << LED_PIN); + /* Enable all LED port pull-ups, except for the LED pin */ + PORT(LED_PORT) = 0xFF - (1 << LED_PIN); + + + /* Disable unused peripherals */ + SPCR &= ~(1< -#include //for recognizing HW_SERIAL - -#warning "modify this to match your USB serial port name" -#define SERIALCOM Serial - -// default UART is Serial (HAVE_SERIAL), look for additional ones -// see if additional HW-SERIAL is available, take biggest for UDPI as default -#if defined(HAVE_HWSERIAL3) -# define HW_SERIAL Serial3 -#elif defined(HAVE_HWSERIAL2) -# define HW_SERIAL Serial2 -#elif defined(HAVE_HWSERIAL1) -# define HW_SERIAL Serial1 -#endif - -//#define HW_SERIAL Serial1 - -// if HW_SERIAL exists change UDPI mode -#if defined(HW_SERIAL) -# define UPDI_IO_TYPE 3 -#endif - -// See if we are compiling for an UPDI chip (xmega3 core) -#if __AVR_ARCH__ == 103 -# define XTINY -#endif - -// Auxiliary Macros -#define CONCAT(A,B) A##B -#if defined XTINY -# define PIN(x) CONCAT(VPORT,x).IN -# define PORT(x) CONCAT(VPORT,x).OUT -# define DDR(x) CONCAT(VPORT,x).DIR -#else -# define PIN(x) CONCAT(PIN,x) -# define PORT(x) CONCAT(PORT,x) -# define DDR(x) CONCAT(DDR,x) -#endif - -// Configuration for AVR with additional UART - only LED pin needed, UDPI via UART -#if defined(HW_SERIAL) -// Leonardo / ProMicro PortB, Pin5 = D9 -# ifndef LED_PORT -# define LED_PORT B -# endif - -# ifndef LED_PIN -# define LED_PIN 5 -# endif -// Configuration for Arduino Mega -#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -# ifndef UPDI_PORT -# define UPDI_PORT D -# endif - -# ifndef UPDI_PIN -# define UPDI_PIN 3 -# endif - -# ifndef LED_PORT -# define LED_PORT B -# endif - -# ifndef LED_PIN -# define LED_PIN 7 -# endif - -# ifndef UPDI_IO_TYPE -# define UPDI_IO_TYPE 2 -# endif - -// Configuration for AVR-0/1 -#elif defined XTINY -# ifndef UPDI_PORT -# define UPDI_PORT B -# endif - -# ifndef UPDI_PIN -# define UPDI_PIN 0 -# endif - -# ifndef LED_PORT -# define LED_PORT B -# endif - -# ifndef LED_PIN -# define LED_PIN 1 -# endif - -# ifndef UPDI_IO_TYPE -# define UPDI_IO_TYPE 2 -# endif -// These are currently used only for AVR-0/1 chips -// Select which USART peripheral is being used for host PC communication -// Also, indicate the port/pin of the HOST_USART Tx pin -# ifndef HOST_USART -# define HOST_USART USART0 -# endif - -# ifndef HOST_TX_PORT -# define HOST_TX_PORT B -# endif - -# ifndef HOST_TX_PIN -# define HOST_TX_PIN 2 -# endif - -// Default configuration (suitable for ATmega 328P and similar devices @16MHz) -#else -# ifndef UPDI_PORT -# define UPDI_PORT D -# endif - -# ifndef UPDI_PIN -# define UPDI_PIN 6 -# endif - -# ifndef LED_PORT -# define LED_PORT B -# endif - -# ifndef LED_PIN -# define LED_PIN 5 -# endif -#endif - - -#ifndef F_CPU -# define F_CPU 16000000U -#endif - -#ifndef UPDI_BAUD -# define UPDI_BAUD 225000U // (max 225000 min approx. F_CPU/100) -#endif - -/* - * Available UPDI I/O types are: - * - * 1 - timer sofware UART: Compatible only with Mega328P and other AVRs with identical 8 bit timer 0. - * Only the OC0A pin can be used for UPDI I/O. Slightly faster upload speed for a given UPDI_BAUD value. - * - * 2 - bitbang software UART: Compatible with many chips and broad choice of UPDI pins are selectable. - * Slightly slower upload speed for a given UPDI_BAUD value. Download speed is the same. - */ -#ifndef UPDI_IO_TYPE -# define UPDI_IO_TYPE 2 -#endif - -// Flash constants class -#if defined XTINY - template - using FLASH = const T; -#else -# include -# define FLASH const PROGMEM flash - - template - class flash { - private: - const T data; - - public: - // normal constructor - constexpr flash (T _data) : data(_data) {} - // default constructor - constexpr flash () : data(0) {} - - operator T() const { - switch (sizeof(T)) { - case 1: return pgm_read_byte(&data); - case 2: return pgm_read_word(&data); - case 4: return pgm_read_dword(&data); - } - } - }; -#endif - -#if defined XTINY - // Note: adapted from MicroChip appnote TB3216 "Getting Started with USART" - constexpr unsigned int baud_reg_val(unsigned long baud) { - return (F_CPU * 64.0) / (16.0 * baud) + 0.5; - } -#else - constexpr unsigned int baud_reg_val(unsigned long baud) { - return F_CPU/(baud * 8.0) - 0.5; - } -#endif - -namespace SYS { - void init(void); - void setLED(void); - void clearLED(void); - void LED_blink (int led_no, int led_blinks, int length_ms); -} - -#endif /* SYS_H_ */ +/* + * sys.h + * + * Created: 02-10-2018 13:07:18 + * Author: JMR_2 + */ + +#ifndef SYS_H_ +#define SYS_H_ + +#include +#include //for recognizing HW_SERIAL + +//#warning "modify this to match your USB serial port name" +#define SERIALCOM Serial + +// default UART is Serial (HAVE_SERIAL), look for additional ones +// see if additional HW-SERIAL is available, take biggest for UDPI as default +#if defined(HAVE_HWSERIAL3) +# define HW_SERIAL Serial3 +#elif defined(HAVE_HWSERIAL2) +# define HW_SERIAL Serial2 +#elif defined(HAVE_HWSERIAL1) +# define HW_SERIAL Serial1 +#endif + +//#define HW_SERIAL Serial1 + +// if HW_SERIAL exists change UDPI mode +#if defined(HW_SERIAL) +# define UPDI_IO_TYPE 3 +#endif + +// See if we are compiling for an UPDI chip (xmega3 core) +#if __AVR_ARCH__ == 103 +# define XTINY +#endif + +// Auxiliary Macros +#define CONCAT(A,B) A##B +#if defined XTINY +# define PIN(x) CONCAT(VPORT,x).IN +# define PORT(x) CONCAT(VPORT,x).OUT +# define DDR(x) CONCAT(VPORT,x).DIR +#else +# define PIN(x) CONCAT(PIN,x) +# define PORT(x) CONCAT(PORT,x) +# define DDR(x) CONCAT(DDR,x) +#endif + +// Configuration for AVR with additional UART - only LED pin needed, UDPI via UART +#if defined(HW_SERIAL) +// Leonardo / ProMicro PortB, Pin5 = D9 +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 5 +# endif +// Configuration for Arduino Mega +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +# ifndef UPDI_PORT +# define UPDI_PORT D +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 3 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 7 +# endif + +# ifndef UPDI_IO_TYPE +# define UPDI_IO_TYPE 2 +# endif + +// Configuration for AVR-0/1 +#elif defined XTINY +# ifndef UPDI_PORT +# define UPDI_PORT B +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 0 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 1 +# endif + +# ifndef UPDI_IO_TYPE +# define UPDI_IO_TYPE 2 +# endif +// These are currently used only for AVR-0/1 chips +// Select which USART peripheral is being used for host PC communication +// Also, indicate the port/pin of the HOST_USART Tx pin +# ifndef HOST_USART +# define HOST_USART USART0 +# endif + +# ifndef HOST_TX_PORT +# define HOST_TX_PORT B +# endif + +# ifndef HOST_TX_PIN +# define HOST_TX_PIN 2 +# endif + +// Default configuration (suitable for ATmega 328P and similar devices @16MHz) +#else +# ifndef UPDI_PORT +# define UPDI_PORT D +# endif + +# ifndef UPDI_PIN +# define UPDI_PIN 6 +# endif + +# ifndef LED_PORT +# define LED_PORT B +# endif + +# ifndef LED_PIN +# define LED_PIN 5 +# endif +#endif + + +#ifndef F_CPU +# define F_CPU 16000000U +#endif + +#ifndef UPDI_BAUD +# define UPDI_BAUD 225000U // (max 225000 min approx. F_CPU/100) +#endif + +/* + * Available UPDI I/O types are: + * + * 1 - timer sofware UART: Compatible only with Mega328P and other AVRs with identical 8 bit timer 0. + * Only the OC0A pin can be used for UPDI I/O. Slightly faster upload speed for a given UPDI_BAUD value. + * + * 2 - bitbang software UART: Compatible with many chips and broad choice of UPDI pins are selectable. + * Slightly slower upload speed for a given UPDI_BAUD value. Download speed is the same. + */ +#ifndef UPDI_IO_TYPE +# define UPDI_IO_TYPE 2 +#endif + +// Flash constants class +#if defined XTINY + template + using FLASH = const T; +#else +# include +# define FLASH const PROGMEM flash + + template + class flash { + private: + const T data; + + public: + // normal constructor + constexpr flash (T _data) : data(_data) {} + // default constructor + constexpr flash () : data(0) {} + + operator T() const { + switch (sizeof(T)) { + case 1: return pgm_read_byte(&data); + case 2: return pgm_read_word(&data); + case 4: return pgm_read_dword(&data); + } + } + }; +#endif + +#if defined XTINY + // Note: adapted from MicroChip appnote TB3216 "Getting Started with USART" + constexpr unsigned int baud_reg_val(unsigned long baud) { + return (F_CPU * 64.0) / (16.0 * baud) + 0.5; + } +#else + constexpr unsigned int baud_reg_val(unsigned long baud) { + return F_CPU/(baud * 8.0) - 0.5; + } +#endif + +namespace SYS { + void init(void); + void setLED(void); + void clearLED(void); + void LED_blink (int led_no, int led_blinks, int length_ms); +} + +#endif /* SYS_H_ */ diff --git a/source/updi_io_uart.cpp b/source/updi_io_uart.cpp index ff0e9bb..91a722b 100644 --- a/source/updi_io_uart.cpp +++ b/source/updi_io_uart.cpp @@ -1,73 +1,73 @@ -/* - * updi_io.cpp - * - * Created: 18-11-2017 10:36:54 - * Author: JMR_2 - */ - - - -// Includes -#include -#include "updi_io.h" -#include "sys.h" - - -#if UPDI_IO_TYPE == 3 -#include - -// Functions -/* Sends regular characters through the UPDI link */ -uint8_t UPDI_io::put(char c) { - HW_SERIAL.write(c); - HW_SERIAL.flush(); - //delayMicroseconds(10); - long start = millis(); - while (!HW_SERIAL.available() && millis() - start < 20) {} - char d = HW_SERIAL.read(); - if (c != d) { - // Serial.println("echo failed! " + String(d, HEX)); - } - return c; -} - -/* Sends special sequences through the UPDI link */ -uint8_t UPDI_io::put(ctrl c) -{ - HW_SERIAL.begin(300, SERIAL_8N1); - switch (c) { - case double_break: - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - break; - case single_break: - HW_SERIAL.write((uint8_t)0x00); - HW_SERIAL.flush(); - break; - default: - break; - } - delay(15); - while (HW_SERIAL.available()) { - HW_SERIAL.read(); - } - HW_SERIAL.begin(230400, SERIAL_8E2); - return 0; -} - -uint8_t UPDI_io::get() { - uint8_t c; - while (!HW_SERIAL.available()) {} - c = HW_SERIAL.read(); - //delayMicroseconds(5); - //Serial.println("get! " + String(c, HEX)); - return c; -} - -void UPDI_io::init(void) -{ - HW_SERIAL.begin(230400, SERIAL_8E2); -} -#endif //UPDI_IO_TYPE == 3 +/* + * updi_io_uart.cpp + * + * Created: 01-02-2020 10:36:54 + * Author: cherry pick from AvrMega_MuxTO + */ + + + +// Includes +#include +#include "updi_io.h" +#include "sys.h" + + +#if UPDI_IO_TYPE == 3 +#include + +// Functions +/* Sends regular characters through the UPDI link */ +uint8_t UPDI_io::put(char c) { + HW_SERIAL.write(c); + HW_SERIAL.flush(); + //delayMicroseconds(10); + long start = millis(); + while (!HW_SERIAL.available() && millis() - start < 20) {} + char d = HW_SERIAL.read(); + if (c != d) { + // Serial.println("echo failed! " + String(d, HEX)); + } + return c; +} + +/* Sends special sequences through the UPDI link */ +uint8_t UPDI_io::put(ctrl c) +{ + HW_SERIAL.begin(300, SERIAL_8N1); + switch (c) { + case double_break: + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + break; + case single_break: + HW_SERIAL.write((uint8_t)0x00); + HW_SERIAL.flush(); + break; + default: + break; + } + delay(15); + while (HW_SERIAL.available()) { + HW_SERIAL.read(); + } + HW_SERIAL.begin(230400, SERIAL_8E2); + return 0; +} + +uint8_t UPDI_io::get() { + uint8_t c; + while (!HW_SERIAL.available()) {} + c = HW_SERIAL.read(); + //delayMicroseconds(5); + //Serial.println("get! " + String(c, HEX)); + return c; +} + +void UPDI_io::init(void) +{ + HW_SERIAL.begin(230400, SERIAL_8E2); +} +#endif //UPDI_IO_TYPE == 3