diff --git a/source/JICE_io.cpp b/source/JICE_io.cpp index 0e2a7bc..76f709d 100644 --- a/source/JICE_io.cpp +++ b/source/JICE_io.cpp @@ -1,99 +1,119 @@ -/* - * stk_io.cpp - * - * Created: 18-11-2017 15:20:29 - * Author: JMR_2 - */ - -// Includes -#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; -#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; -#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< +//#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 uint8_t put(char c); @@ -21,4 +26,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/JTAG2.cpp b/source/JTAG2.cpp index a1d2780..ff6307e 100644 --- a/source/JTAG2.cpp +++ b/source/JTAG2.cpp @@ -1,369 +1,386 @@ -/* - * 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; - -// Local objects -namespace { - // *** Local 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); - - // *** Signature response message *** - FLASH sgn_resp[29] { JTAG2::RSP_SIGN_ON, 1, - 1, JTAG2::PARAM_FW_VER_M_MIN_VAL, JTAG2::PARAM_FW_VER_M_MAJ_VAL, JTAG2::PARAM_HW_VER_M_VAL, - 1, JTAG2::PARAM_FW_VER_S_MIN_VAL, JTAG2::PARAM_FW_VER_S_MAJ_VAL, JTAG2::PARAM_HW_VER_S_VAL, - 0, 0, 0, 0, 0, 0, - 'J', 'T', 'A', 'G', 'I', 'C', 'E', ' ', 'm', 'k', 'I', 'I', 0}; -} - -// *** 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 *** - - 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]; - } - -# ifdef READ_SIB - // Append UPDI System Information Block (SIB) to sign-on response for debugging purposes - packet.size_word[0] += READ_SIB; - uint8_t (& sib)[READ_SIB] = *(uint8_t (*)[READ_SIB]) (packet.body + sizeof(sgn_resp)); - UPDI::read_sib(sib); -# endif - } - - 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; + +// Local objects +namespace { + // *** Local 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); + + // *** Signature response message *** + FLASH sgn_resp[29] { JTAG2::RSP_SIGN_ON, 1, + 1, JTAG2::PARAM_FW_VER_M_MIN_VAL, JTAG2::PARAM_FW_VER_M_MAJ_VAL, JTAG2::PARAM_HW_VER_M_VAL, + 1, JTAG2::PARAM_FW_VER_S_MIN_VAL, JTAG2::PARAM_FW_VER_S_MAJ_VAL, JTAG2::PARAM_HW_VER_S_VAL, + 0, 0, 0, 0, 0, 0, + 'J', 'T', 'A', 'G', 'I', 'C', 'E', ' ', 'm', 'k', 'I', 'I', 0}; +} + +// *** 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 *** + +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]; + } + +# ifdef READ_SIB + // Append UPDI System Information Block (SIB) to sign-on response for debugging purposes + packet.size_word[0] += READ_SIB; + uint8_t (& sib)[READ_SIB] = *(uint8_t (*)[READ_SIB]) (packet.body + sizeof(sgn_resp)); + UPDI::read_sib(sib); +# endif + } + + 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/JTAG2.h b/source/JTAG2.h index 4aa9794..d106182 100644 --- a/source/JTAG2.h +++ b/source/JTAG2.h @@ -152,4 +152,4 @@ namespace JTAG2 { -#endif /* STK_H_ */ \ No newline at end of file +#endif /* STK_H_ */ diff --git a/source/UPDI_lo_lvl.h b/source/UPDI_lo_lvl.h index ec36b53..78a90af 100644 --- a/source/UPDI_lo_lvl.h +++ b/source/UPDI_lo_lvl.h @@ -10,7 +10,12 @@ #define UPDI_LO_LVL_H_ #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 @@ -84,4 +89,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 92ccde4..4caea0a 100644 --- a/source/jtag2updi.cpp +++ b/source/jtag2updi.cpp @@ -1,91 +1,121 @@ -/* - * j2updi.cpp - * - * Created: 11-11-2017 22:29:58 - * Author : JMR_2 - */ - -// Includes -#include "sys.h" -#include "updi_io.h" -#include "JICE_io.h" -#include "JTAG2.h" - -/* Internal stuff */ -namespace { - // Prototypes - void setup(); - void loop(); -} - -int main(void) -{ - setup(); - loop(); -} - -/* Internal stuff */ -namespace { - inline void setup() { - /* Initialize MCU */ - SYS::init(); - - /* Initialize serial links */ - JICE_io::init(); - UPDI_io::init(); - } - - - inline void loop() { - 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(); - } - } -} \ No newline at end of file +/* + * 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 f061eed..e90f6ea 100644 --- a/source/sys.cpp +++ b/source/sys.cpp @@ -1,69 +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 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 - /* 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); -#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< - -// 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 Arduino Mega -#if 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); -} - -#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_ */ \ No newline at end of file diff --git a/source/updi_io.cpp b/source/updi_io.cpp index f47c459..8e9db80 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,5 @@ namespace { } } - -#endif //__AVR_ATmega16__ + +#endif //UPDI_IO_TYPE == 1 diff --git a/source/updi_io_uart.cpp b/source/updi_io_uart.cpp new file mode 100644 index 0000000..91a722b --- /dev/null +++ b/source/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/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