/* j2updi.cpp Created: 11-11-2017 22:29:58 Author : JMR_2 Ported to generic Arduino framework by the Arduino Team - 2019 */ /* Compile with fqbn=arduino:samd:muxto:float=default,config=enabled,clock=internal_usb,timer=timer_732Hz,bootloader=4kb,serial=two_uart,usb=cdc to obtain the binary for Serial-to-USB converter + UPDI programmer on the Arduino Nano Every (MuxTO for brevity) Since the "sketch" is (almost) pure Arduino it can be ported easily to other architectures (on chips with two serial ports) The bitbanged UPDI layer is being reworked to make it compatible with chips with just one UART (eg. atmega 32u4) */ // Includes #include "sys.h" #include "lock.h" #include "updi_io.h" #include "JICE_io.h" #include "JTAG2.h" #include "UPDI_hi_lvl.h" uint16_t serial_mode = SERIAL_8N1; unsigned long baudrate = 115200; struct lock q; void setup() { /* Initialize MCU */ // pinMode(LED_BUILTIN, OUTPUT); /* Initialize serial links */ JICE_io::init(); UPDI_io::init(); Serial1.begin(baudrate, serial_mode); lock_init(&q); JTAG2::sign_on(); } //#define DEBUG; //long blink_timer = 0; //long blink_delay = 1000; void loop() { volatile bool updi_mode = false; unsigned long updi_mode_start = 0; unsigned long updi_mode_end = 0; unsigned long tnow = 0; uint8_t stopbits_new = 1; uint8_t paritytype_new = 0; uint8_t numbits_new = 8; unsigned long baudrate_new = 115200; uint8_t stopbits = 1; uint8_t paritytype = 0; uint8_t numbits = 8; int8_t dtr = -1; int8_t rts = -1; int8_t dtr_new = -1; int8_t rts_new = -1; int cav1=0; int cav=0; bool serialNeedReconfiguration = false; char support_buffer[64]; #ifdef DEBUG if (millis() - blink_timer > blink_delay) { SYS::toggleLED(); blink_timer = millis(); } #endif if (!updi_mode){ // == false) { //blink_delay = 1000; if (int c1 = Serial1.available()) { lock(&q); cav=Serial.availableForWrite(); if (c1 > cav) { c1 = cav; } unlock(&q); Serial1.readBytes(support_buffer, c1); Serial.write(support_buffer, c1); } if (int c = Serial.available()) { lock(&q); cav1=Serial1.availableForWrite(); if (c > cav1) { c = cav1; } unlock(&q); Serial.readBytes(support_buffer, c); Serial1.write(support_buffer, c); } static const uint16_t modemasks[3]={~HARDSER_STOP_BIT_MASK,~HARDSER_PARITY_MASK,~HARDSER_DATA_MASK}; stopbits_new=Serial.stopbits(); if (stopbits_new != stopbits) { //serial_mode &= ~HARDSER_STOP_BIT_MASK; stopbits = stopbits_new; serialNeedReconfiguration = true; if (stopbits_new==1 || stopbits_new==2){ serial_mode =(serial_mode & modemasks[0])|( (stopbits_new==1) ? HARDSER_STOP_BIT_1 : HARDSER_STOP_BIT_2); } // switch (stopbits) { // case 1: // serial_mode |= HARDSER_STOP_BIT_1; // break; // case 2: // serial_mode |= HARDSER_STOP_BIT_2; // break; // } } static const uint16_t paritytypecode[3]={HARDSER_PARITY_NONE,HARDSER_PARITY_EVEN,HARDSER_PARITY_ODD}; paritytype_new=Serial.paritytype(); if (paritytype_new!= paritytype) { //serial_mode &= ~HARDSER_PARITY_MASK; paritytype = paritytype_new; serialNeedReconfiguration = true; if (paritytype_new == 0 || paritytype_new==1 || paritytype_new==2){ serial_mode = (serial_mode & modemasks[1]) | ( paritytypecode[paritytype_new]); } // switch (paritytype) { // case 0: // serial_mode |= HARDSER_PARITY_NONE; // break; // case 1: // serial_mode |= HARDSER_PARITY_EVEN; // break; // case 2: // serial_mode |= HARDSER_PARITY_ODD; // break; // } } static const uint16_t numbitscode_5[4]={HARDSER_DATA_5,HARDSER_DATA_6,HARDSER_DATA_7,HARDSER_DATA_8}; numbits_new=Serial.numbits(); if (numbits_new != numbits) { //serial_mode &= ~HARDSER_DATA_MASK; numbits = numbits_new; serialNeedReconfiguration = true; if (numbits_new==5||numbits_new==6||numbits_new==7||numbits_new==8){ serial_mode =(serial_mode&modemasks[2])|numbitscode_5[numbits_new-5]; } // switch (numbits) { // case 5: // serial_mode |= HARDSER_DATA_5; // break; // case 6: // serial_mode |= HARDSER_DATA_6; // break; // case 7: // serial_mode |= HARDSER_DATA_7; // break; // case 8: // serial_mode |= HARDSER_DATA_8; // break; // } } dtr_new=Serial.dtr(); if (baudrate == 1200 && dtr_new== 0 && (millis() - updi_mode_end > 200)) { // don't reenter here if you just finished flashing updi_mode = true; updi_mode_start = millis(); updi_mode_end = 0; } baudrate_new=Serial.baud(); if (baudrate_new != baudrate || serialNeedReconfiguration || dtr_new != dtr) { dtr = dtr_new; if (dtr_new == 1) { baudrate = baudrate_new; Serial1.end(); if (baudrate != 1200) { Serial1.begin(baudrate, serial_mode); serialNeedReconfiguration = false; // Request reset UPDI::stcs(UPDI::reg::ASI_Reset_Request, UPDI::RESET_ON); // Release reset (System remains in reset state until released) UPDI::stcs(UPDI::reg::ASI_Reset_Request, UPDI::RESET_OFF); } } } return; } //if (updi_mode == true) { else{ // updi_mode cannot last more than 1 minute; in that case, break forcibly tnow=millis(); if ((updi_mode_end != 0 && (tnow - updi_mode_end) > 500) || ((tnow - updi_mode_start) > 60000)) { updi_mode = false; baudrate = -1; return; } //blink_delay = 100; // Receive command if (!JTAG2::receive()) { return; } // 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(); updi_mode_end = millis(); 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(); } }