Basic read operations implemented

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/branches/serialupdi@1513 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Dawid Buchwald 2021-12-08 12:36:58 +00:00 committed by Marius Greuel
parent b6e72dce4c
commit 748bee8ecf
14 changed files with 3194 additions and 0 deletions

View File

@ -183,6 +183,17 @@ libavrdude_a_SOURCES = \
tpi.h \
usbasp.c \
usbasp.h \
serialupdi.c \
serialupdi.h \
updi_constants.h \
updi_link.c \
updi_link.h \
updi_state.c \
updi_state.h \
updi_readwrite.c \
updi_readwrite.h \
updi_nvm.c \
updi_nvm.h \
usbdevs.h \
usb_hidapi.c \
usb_libusb.c \

View File

@ -613,6 +613,13 @@ programmer
reset = 3; # TMS 7
;
programmer
id = "serialupdi";
desc = "SerialUPDI";
type = "serialupdi";
connection_type = serial;
;
programmer
id = "avrisp";
desc = "Atmel AVR ISP";

253
avrdude/serialupdi.c Normal file
View File

@ -0,0 +1,253 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Interface to the SerialUPDI programmer.
*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#include "ac_cfg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
#include "avrdude.h"
#include "libavrdude.h"
#include "serialupdi.h"
#include "updi_link.h"
#include "updi_state.h"
#include "updi_readwrite.h"
static void serialupdi_setup(PROGRAMMER * pgm)
{
if ((pgm->cookie = malloc(sizeof(updi_state))) == 0) {
avrdude_message(MSG_INFO,
"%s: serialupdi_setup(): Out of memory allocating private data\n",
progname);
exit(1);
}
memset(pgm->cookie, 0, sizeof(updi_state));
updi_set_datalink_mode(pgm, UPDI_LINK_MODE_16BIT);
}
static void serialupdi_teardown(PROGRAMMER * pgm)
{
free(pgm->cookie);
}
static int serialupdi_open(PROGRAMMER * pgm, char * port)
{
strcpy(pgm->port, port);
return updi_link_open(pgm);
}
static int serialupdi_decode_sib(updi_sib_info * sib_info)
{
char * str_ptr;
sib_info->sib_string[SIB_INFO_STRING_LENGTH]=0;
avrdude_message(MSG_DEBUG, "%s: Received SIB: [%s]\n", progname, sib_info->sib_string);
memset(sib_info->family_string, 0, SIB_INFO_FAMILY_LENGTH+1);
memset(sib_info->nvm_string, 0, SIB_INFO_NVM_LENGTH+1);
memset(sib_info->debug_string, 0, SIB_INFO_DEBUG_LENGTH+1);
memset(sib_info->pdi_string, 0, SIB_INFO_PDI_LENGTH+1);
memset(sib_info->pdi_string, 0, SIB_INFO_PDI_LENGTH+1);
memset(sib_info->extra_string, 0, SIB_INFO_EXTRA_LENGTH+1);
memcpy(sib_info->family_string, sib_info->sib_string, SIB_INFO_FAMILY_LENGTH);
memcpy(sib_info->nvm_string, sib_info->sib_string + 8, SIB_INFO_NVM_LENGTH);
memcpy(sib_info->debug_string, sib_info->sib_string + 11, SIB_INFO_DEBUG_LENGTH);
memcpy(sib_info->pdi_string, sib_info->sib_string + 15, SIB_INFO_PDI_LENGTH);
strcpy(sib_info->extra_string, (char *)sib_info->sib_string + 19);
str_ptr = strstr(sib_info->nvm_string, ":");
if (!str_ptr) {
avrdude_message(MSG_INFO, "%s: Incorrect format of NVM string\n", progname);
return -1;
}
sib_info->nvm_version = *(str_ptr+1);
str_ptr = strstr(sib_info->debug_string, ":");
if (!str_ptr) {
avrdude_message(MSG_INFO, "%s: Incorrect format of DEBUG string\n", progname);
return -1;
}
sib_info->debug_version = *(str_ptr+1);
avrdude_message(MSG_DEBUG, "%s: Device family ID: %s\n", progname, sib_info->family_string);
avrdude_message(MSG_DEBUG, "%s: NVM interface: %s\n", progname, sib_info->nvm_string);
avrdude_message(MSG_DEBUG, "%s: Debug interface: %s\n", progname, sib_info->debug_string);
avrdude_message(MSG_DEBUG, "%s: PDI oscillator: %s\n", progname, sib_info->pdi_string);
avrdude_message(MSG_DEBUG, "%s: Extra information: %s\n", progname, sib_info->extra_string);
switch (sib_info->nvm_version) {
case '0':
avrdude_message(MSG_INFO, "%s: NVM type 0: 16-bit, page oriented write\n", progname);
break;
case '2':
avrdude_message(MSG_INFO, "%s: NVM type 2: 24-bit, word oriented write\n", progname);
break;
case '3':
avrdude_message(MSG_INFO, "%s: NVM type 3: 16-bit, page oriented\n", progname);
break;
default:
avrdude_message(MSG_INFO, "%s: Unsupported NVM type: %c, please update software\n", progname, sib_info->nvm_version);
return -1;
}
return 0;
}
static void serialupdi_close(PROGRAMMER * pgm)
{
updi_link_close(pgm);
}
static int serialupdi_initialize(PROGRAMMER * pgm, AVRPART * p)
{
updi_sib_info * sib_info = updi_get_sib_info(pgm);
if (updi_link_init(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI link initialization failed\n", progname);
return -1;
}
avrdude_message(MSG_INFO, "%s: UPDI link initialization OK\n", progname);
if (updi_read_sib(pgm, sib_info->sib_string, 32) < 0) {
avrdude_message(MSG_INFO, "%s: Read SIB operation failed\n", progname);
return -1;
}
if (serialupdi_decode_sib(sib_info) < 0) {
avrdude_message(MSG_INFO, "%s: Decode SIB_INFO failed\n", progname);
return -1;
}
updi_set_nvm_mode(pgm, sib_info->nvm_version);
if (sib_info->nvm_version == '2') {
updi_set_datalink_mode(pgm, UPDI_LINK_MODE_24BIT);
} else {
updi_set_datalink_mode(pgm, UPDI_LINK_MODE_16BIT);
}
return 0;
}
static void serialupdi_disable(PROGRAMMER * pgm)
{
/* Do nothing. */
return;
}
static void serialupdi_enable(PROGRAMMER * pgm)
{
/* Do nothing. */
return;
}
static void serialupdi_display(PROGRAMMER * pgm, const char * p)
{
return;
}
static int serialupdi_cmd(PROGRAMMER * pgm, const unsigned char * cmd,
unsigned char * res)
{
avrdude_message(MSG_INFO, "%s: error: cmd %s[%s] not implemented yet\n",
progname, cmd, res);
return -1;
}
static int serialupdi_program_enable(PROGRAMMER * pgm, AVRPART * p)
{
avrdude_message(MSG_INFO, "%s: error: program enable not implemented yet\n",
progname);
return -1;
}
static int serialupdi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
{
avrdude_message(MSG_INFO, "%s: error: chip erase not implemented yet\n",
progname);
return -1;
}
static int serialupdi_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char * value)
{
// avrdude_message(MSG_INFO, "%s: error: read byte not implemented yet\n",
// progname);
return updi_read_byte(pgm, mem->offset + addr, value);
// return -1;
}
static int serialupdi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
{
avrdude_message(MSG_INFO, "%s: error: paged load not implemented yet\n",
progname);
return -1;
}
static int serialupdi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
{
avrdude_message(MSG_INFO, "%s: error: paged write not implemented yet\n",
progname);
return -1;
}
void serialupdi_initpgm(PROGRAMMER * pgm)
{
strcpy(pgm->type, "serialupdi");
/*
* mandatory functions
*/
pgm->initialize = serialupdi_initialize;
pgm->display = serialupdi_display;
pgm->enable = serialupdi_enable;
pgm->disable = serialupdi_disable;
pgm->program_enable = serialupdi_program_enable;
pgm->chip_erase = serialupdi_chip_erase;
pgm->cmd = serialupdi_cmd;
pgm->open = serialupdi_open;
pgm->close = serialupdi_close;
pgm->read_byte = serialupdi_read_byte;
pgm->write_byte = avr_write_byte_default;
/*
* optional functions
*/
pgm->paged_write = serialupdi_paged_write;
pgm->paged_load = serialupdi_paged_load;
pgm->setup = serialupdi_setup;
pgm->teardown = serialupdi_teardown;
}
const char serialupdi_desc[] = "Driver for SerialUPDI programmers";

43
avrdude/serialupdi.h Normal file
View File

@ -0,0 +1,43 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#ifndef serialupdi_h
#define serialupdi_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const char serialupdi_desc[];
void serialupdi_initpgm (PROGRAMMER * pgm);
#ifdef __cplusplus
}
#endif
#endif /* serialupdi_h */

156
avrdude/updi_constants.h Normal file
View File

@ -0,0 +1,156 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#ifndef updi_constants_h
#define updi_constants_h
#define UPDI_BREAK 0x00
#define UPDI_LDS 0x00
#define UPDI_STS 0x40
#define UPDI_LD 0x20
#define UPDI_ST 0x60
#define UPDI_LDCS 0x80
#define UPDI_STCS 0xC0
#define UPDI_REPEAT 0xA0
#define UPDI_KEY 0xE0
#define UPDI_PTR 0x00
#define UPDI_PTR_INC 0x04
#define UPDI_PTR_ADDRESS 0x08
#define UPDI_ADDRESS_8 0x00
#define UPDI_ADDRESS_16 0x04
#define UPDI_ADDRESS_24 0x08
#define UPDI_DATA_8 0x00
#define UPDI_DATA_16 0x01
#define UPDI_DATA_24 0x02
#define UPDI_KEY_SIB 0x04
#define UPDI_KEY_KEY 0x00
#define UPDI_KEY_64 0x00
#define UPDI_KEY_128 0x01
#define UPDI_KEY_256 0x02
#define UPDI_SIB_8BYTES UPDI_KEY_64
#define UPDI_SIB_16BYTES UPDI_KEY_128
#define UPDI_SIB_32BYTES UPDI_KEY_256
#define UPDI_REPEAT_BYTE 0x00
#define UPDI_REPEAT_WORD 0x01
#define UPDI_PHY_SYNC 0x55
#define UPDI_PHY_ACK 0x40
#define UPDI_MAX_REPEAT_SIZE (0xFF+1) // Repeat counter of 1-byte, with off-by-one counting
//# CS and ASI Register Address map
#define UPDI_CS_STATUSA 0x00
#define UPDI_CS_STATUSB 0x01
#define UPDI_CS_CTRLA 0x02
#define UPDI_CS_CTRLB 0x03
#define UPDI_ASI_KEY_STATUS 0x07
#define UPDI_ASI_RESET_REQ 0x08
#define UPDI_ASI_CTRLA 0x09
#define UPDI_ASI_SYS_CTRLA 0x0A
#define UPDI_ASI_SYS_STATUS 0x0B
#define UPDI_ASI_CRC_STATUS 0x0C
#define UPDI_CTRLA_IBDLY_BIT 7
#define UPDI_CTRLB_CCDETDIS_BIT 3
#define UPDI_CTRLB_UPDIDIS_BIT 2
#define UPDI_KEY_NVM "NVMProg "
#define UPDI_KEY_CHIPERASE "NVMErase"
#define UPDI_KEY_UROW "NVMUs&te"
#define UPDI_ASI_STATUSA_REVID 4
#define UPDI_ASI_STATUSB_PESIG 0
#define UPDI_ASI_KEY_STATUS_CHIPERASE 3
#define UPDI_ASI_KEY_STATUS_NVMPROG 4
#define UPDI_ASI_KEY_STATUS_UROWWRITE 5
#define UPDI_ASI_SYS_STATUS_RSTSYS 5
#define UPDI_ASI_SYS_STATUS_INSLEEP 4
#define UPDI_ASI_SYS_STATUS_NVMPROG 3
#define UPDI_ASI_SYS_STATUS_UROWPROG 2
#define UPDI_ASI_SYS_STATUS_LOCKSTATUS 0
#define UPDI_ASI_SYS_CTRLA_UROW_FINAL 1
#define UPDI_RESET_REQ_VALUE 0x59
// FLASH CONTROLLER
#define UPDI_NVMCTRL_CTRLA 0x00
#define UPDI_NVMCTRL_CTRLB 0x01
#define UPDI_NVMCTRL_STATUS 0x02
#define UPDI_NVMCTRL_INTCTRL 0x03
#define UPDI_NVMCTRL_INTFLAGS 0x04
#define UPDI_NVMCTRL_DATAL 0x06
#define UPDI_NVMCTRL_DATAH 0x07
#define UPDI_NVMCTRL_ADDRL 0x08
#define UPDI_NVMCTRL_ADDRH 0x09
// NVMCTRL v0 CTRLA
#define UPDI_V0_NVMCTRL_CTRLA_NOP 0x00
#define UPDI_V0_NVMCTRL_CTRLA_WRITE_PAGE 0x01
#define UPDI_V0_NVMCTRL_CTRLA_ERASE_PAGE 0x02
#define UPDI_V0_NVMCTRL_CTRLA_ERASE_WRITE_PAGE 0x03
#define UPDI_V0_NVMCTRL_CTRLA_PAGE_BUFFER_CLR 0x04
#define UPDI_V0_NVMCTRL_CTRLA_CHIP_ERASE 0x05
#define UPDI_V0_NVMCTRL_CTRLA_ERASE_EEPROM 0x06
#define UPDI_V0_NVMCTRL_CTRLA_WRITE_FUSE 0x07
// NVMCTRL v2 CTRLA
#define UPDI_V2_NVMCTRL_CTRLA_NOCMD 0x00
#define UPDI_V2_NVMCTRL_CTRLA_FLASH_WRITE 0x02
#define UPDI_V2_NVMCTRL_CTRLA_FLASH_PAGE_ERASE 0x08
#define UPDI_V2_NVMCTRL_CTRLA_EEPROM_ERASE_WRITE 0x13
#define UPDI_V2_NVMCTRL_CTRLA_CHIP_ERASE 0x20
#define UPDI_V2_NVMCTRL_CTRLA_EEPROM_ERASE 0x30
// NVMCTRL v3 CTRLA
#define UPDI_V3_NVMCTRL_CTRLA_NOCMD 0x00
#define UPDI_V3_NVMCTRL_CTRLA_NOP 0x01
#define UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_WRITE 0x04
#define UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_ERASE_WRITE 0x05
#define UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_ERASE 0x08
#define UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_BUFFER_CLEAR 0x0F
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_PAGE_WRITE 0x14
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_PAGE_ERASE_WRITE 0x15
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_PAGE_ERASE 0x17
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_PAGE_BUFFER_CLEAR 0x1F
#define UPDI_V3_NVMCTRL_CTRLA_CHIP_ERASE 0x20
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_ERASE 0x30
#define UPDI_NVM_STATUS_WRITE_ERROR 2
#define UPDI_NVM_STATUS_EEPROM_BUSY 1
#define UPDI_NVM_STATUS_FLASH_BUSY 0
#endif /* updi_constants_h */

825
avrdude/updi_link.c Normal file
View File

@ -0,0 +1,825 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#include "ac_cfg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
#include "avrdude.h"
#include "libavrdude.h"
#include "updi_link.h"
#include "updi_constants.h"
#include "updi_state.h"
#include <sys/time.h>
void msleep(int tms)
{
struct timeval tv;
tv.tv_sec = tms / 1000;
tv.tv_usec = (tms % 1000) * 1000;
select (0, NULL, NULL, NULL, &tv);
}
static int updi_physical_open(PROGRAMMER* pgm, int baudrate, unsigned long cflags)
{
serial_recv_timeout = 100;
union pinfo pinfo;
pinfo.serialinfo.baud = baudrate;
pinfo.serialinfo.cflags = cflags;
avrdude_message(MSG_DEBUG, "%s: Opening serial port...\n", progname);
if (serial_open(pgm->port, pinfo, &pgm->fd)==-1) {
avrdude_message(MSG_INFO, "%s: Serial port open failed!\n", progname);
return -1;
}
/*
* drain any extraneous input
*/
serial_drain(&pgm->fd, 0);
return 0;
}
static void updi_physical_close(PROGRAMMER* pgm)
{
serial_close(&pgm->fd);
pgm->fd.ifd = -1;
}
static int updi_physical_send(PROGRAMMER * pgm, unsigned char * buf, size_t len)
{
size_t i;
int rv;
avrdude_message(MSG_DEBUG, "%s: Sending %lu bytes [", progname, len);
for (i=0; i<len; i++) {
avrdude_message(MSG_DEBUG, "0x%02x", buf[i]);
if (i<len-1) {
avrdude_message(MSG_DEBUG, ", ");
}
}
avrdude_message(MSG_DEBUG, "]\n");
rv = serial_send(&pgm->fd, buf, len);
serial_recv(&pgm->fd, buf, len);
return rv;
}
static int updi_physical_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len)
{
size_t i;
int rv;
rv = serial_recv(&pgm->fd, buf, len);
if (rv < 0) {
avrdude_message(MSG_DEBUG,
"%s: serialupdi_recv(): programmer is not responding\n",
progname);
return -1;
}
avrdude_message(MSG_DEBUG, "%s: Received %lu bytes [", progname, len);
for (i=0; i<len; i++) {
avrdude_message(MSG_DEBUG, "0x%02x", buf[i]);
if (i<len-1) {
avrdude_message(MSG_DEBUG, ", ");
}
}
avrdude_message(MSG_DEBUG, "]\n");
return len;
}
static int updi_physical_send_double_break(PROGRAMMER * pgm)
{
unsigned char buffer[1];
avrdude_message(MSG_DEBUG, "%s: Sending double break\n", progname);
updi_physical_close(pgm);
if (updi_physical_open(pgm, 300, SERIAL_8E1)==-1) {
return -1;
}
buffer[0] = UPDI_BREAK;
serial_send(&pgm->fd, buffer, 1);
serial_recv(&pgm->fd, buffer, 1);
msleep(100);
buffer[0] = UPDI_BREAK;
serial_send(&pgm->fd, buffer, 1);
serial_recv(&pgm->fd, buffer, 1);
updi_physical_close(pgm);
return updi_physical_open(pgm, pgm->baudrate? pgm->baudrate: 115200, SERIAL_8E2);
}
int updi_physical_sib(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size)
{
/*
def sib(self):
"""
System information block is just a string coming back from a SIB command
"""
self.send([
constants.UPDI_PHY_SYNC,
constants.UPDI_KEY | constants.UPDI_KEY_SIB | constants.UPDI_SIB_32BYTES])
return self.ser.readline()
*/
unsigned char send_buffer[2];
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_KEY | UPDI_KEY_SIB | UPDI_SIB_32BYTES;
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_INFO, "%s: SIB request send failed\n", progname);
return -1;
}
return updi_physical_recv(pgm, buffer, size);
}
int updi_link_open(PROGRAMMER * pgm)
{
return updi_physical_open(pgm, pgm->baudrate? pgm->baudrate: 115200,
(SERIAL_CS8 | SERIAL_CSTOPB | SERIAL_CREAD | SERIAL_PARENB | SERIAL_CLOCAL));
}
void updi_link_close(PROGRAMMER * pgm)
{
updi_physical_close(pgm);
}
static int updi_link_init_session_parameters(PROGRAMMER * pgm)
{
/*
def _init_session_parameters(self):
"""
Set the inter-byte delay bit and disable collision detection
"""
self.stcs(constants.UPDI_CS_CTRLB, 1 << constants.UPDI_CTRLB_CCDETDIS_BIT)
self.stcs(constants.UPDI_CS_CTRLA, 1 << constants.UPDI_CTRLA_IBDLY_BIT)
*/
if (updi_link_stcs(pgm, UPDI_CS_CTRLB, 1 << UPDI_CTRLB_CCDETDIS_BIT) < 0) {
return -1;
}
if (updi_link_stcs(pgm, UPDI_CS_CTRLA, 1 << UPDI_CTRLA_IBDLY_BIT) < 0) {
return -1;
}
return 0;
}
static int updi_link_check(PROGRAMMER * pgm)
{
/*
def _check_datalink(self):
"""
Check UPDI by loading CS STATUSA
"""
try:
if self.ldcs(constants.UPDI_CS_STATUSA) != 0:
self.logger.info("UPDI init OK")
return True
except PymcuprogError:
self.logger.warning("Check failed")
return False
self.logger.info("UPDI not OK - reinitialisation required")
return False
*/
int result;
uint8_t value;
result = updi_link_ldcs(pgm, UPDI_CS_STATUSA, &value);
if (result < 0) {
avrdude_message(MSG_DEBUG, "%s: Check failed\n", progname);
return -1;
} else {
if (value > 0) {
avrdude_message(MSG_DEBUG, "%s: UDPI init OK\n", progname);
return 0;
} else {
avrdude_message(MSG_DEBUG, "%s: UDPI not OK - reinitialisation required\n", progname);
return -1;
}
}
}
int updi_link_init(PROGRAMMER * pgm)
{
/*
def init_datalink(self):
"""
Init DL layer
"""
self._init_session_parameters()
# Check
if not self._check_datalink():
# Send double break if all is not well, and re-check
self.updi_phy.send_double_break()
self._init_session_parameters()
if not self._check_datalink():
raise PymcuprogError("UPDI initialisation failed")
*/
if (updi_link_init_session_parameters(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: Session initialisation failed\n", progname);
return -1;
}
if (updi_link_check(pgm) < 0) {
avrdude_message(MSG_DEBUG, "%s: Datalink not active, resetting...\n", progname);
if (updi_physical_send_double_break(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: Datalink initialisation failed\n", progname);
return -1;
}
if (updi_link_init_session_parameters(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: Session initialisation failed\n", progname);
return -1;
}
if (updi_link_check(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: Restoring datalink failed\n", progname);
return -1;
}
}
return 0;
}
int updi_link_ldcs(PROGRAMMER * pgm, uint8_t address, uint8_t * value)
{
/*
def ldcs(self, address):
"""
Load data from Control/Status space
:param address: address to load
"""
self.logger.debug("LDCS from 0x%02X", address)
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_LDCS | (address & 0x0F)])
response = self.updi_phy.receive(self.LDCS_RESPONSE_BYTES)
numbytes_received = len(response)
if numbytes_received != self.LDCS_RESPONSE_BYTES:
raise PymcuprogError("Unexpected number of bytes in response: "
"{} byte(s) expected {} byte(s)".format(numbytes_received, self.LDCS_RESPONSE_BYTES))
return response[0]
*/
unsigned char buffer[2];
int result;
avrdude_message(MSG_DEBUG, "%s: LDCS from 0x%02X\n", progname, address);
buffer[0]=UPDI_PHY_SYNC;
buffer[1]=UPDI_LDCS | (address & 0x0F);
if (updi_physical_send(pgm, buffer, 2) < 0) {
avrdude_message(MSG_INFO, "%s: LDCS send operation failed\n", progname);
return -1;
}
result = updi_physical_recv(pgm, buffer, 1);
if (result != 1) {
if (result >= 0) {
avrdude_message(MSG_INFO, "%s: Incorrect response size, received %d instead of %d bytes\n", progname, result, 1);
}
return -1;
}
* value = buffer[0];
return 0;
}
int updi_link_stcs(PROGRAMMER * pgm, uint8_t address, uint8_t value)
{
/*
def stcs(self, address, value):
"""
Store a value to Control/Status space
:param address: address to store to
:param value: value to write
"""
self.logger.debug("STCS to 0x%02X", address)
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_STCS | (address & 0x0F), value])
*/
unsigned char buffer[3];
avrdude_message(MSG_DEBUG, "%s: STCS 0x%02X to address 0x%02X\n", progname, value, address);
buffer[0] = UPDI_PHY_SYNC;
buffer[1] = UPDI_STCS | (address & 0x0F);
buffer[2] = value;
return updi_physical_send(pgm, buffer, 3);
}
int updi_link_ld_ptr_inc(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size)
{
/*
def ld_ptr_inc(self, size):
"""
Loads a number of bytes from the pointer location with pointer post-increment
:param size: number of bytes to load
:return: values read
"""
self.logger.debug("LD8 from ptr++")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_LD | constants.UPDI_PTR_INC |
constants.UPDI_DATA_8])
return self.updi_phy.receive(size)
*/
unsigned char send_buffer[2];
avrdude_message(MSG_DEBUG, "%s: LD8 from ptr++\n", progname);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_LD | UPDI_PTR_INC | UPDI_DATA_8;
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_INFO, "%s: LD_PTR_INC send operation failed\n", progname);
return -1;
}
return updi_physical_recv(pgm, buffer, size);
}
int updi_link_ld_ptr_inc16(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words)
{
/*
def ld_ptr_inc16(self, words):
"""
Load a 16-bit word value from the pointer location with pointer post-increment
:param words: number of words to load
:return: values read
"""
self.logger.debug("LD16 from ptr++")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_LD | constants.UPDI_PTR_INC |
constants.UPDI_DATA_16])
return self.updi_phy.receive(words << 1)
*/
unsigned char send_buffer[2];
avrdude_message(MSG_DEBUG, "%s: LD16 from ptr++\n", progname);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_LD | UPDI_PTR_INC | UPDI_DATA_16;
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_INFO, "%s: LD_PTR_INC send operation failed\n", progname);
return -1;
}
return updi_physical_recv(pgm, buffer, words << 2);
}
int updi_link_st_ptr_inc(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size)
{
/*
def st_ptr_inc(self, data):
"""
Store data to the pointer location with pointer post-increment
:param data: data to store
"""
self.logger.debug("ST8 to *ptr++")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_ST | constants.UPDI_PTR_INC | constants.UPDI_DATA_8,
data[0]])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("ACK error with st_ptr_inc")
num = 1
while num < len(data):
self.updi_phy.send([data[num]])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st_ptr_inc")
num += 1
*/
unsigned char send_buffer[3];
unsigned char recv_buffer[1];
int response;
int num = 1;
avrdude_message(MSG_DEBUG, "%s: ST8 to *ptr++\n", progname);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_ST | UPDI_PTR_INC | UPDI_DATA_8;
send_buffer[2] = buffer[0];
if (updi_physical_send(pgm, send_buffer, 3) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR_INC send operation failed\n", progname);
return -1;
}
response = updi_physical_recv(pgm, recv_buffer, 1);
if (response != 1 || recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_INFO, "%s: ACK was expected but not received\n", progname);
return -1;
}
while (num < size) {
send_buffer[0]=buffer[num];
if (updi_physical_send(pgm, send_buffer, 1) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR_INC data send operation failed\n", progname);
return -1;
}
response = updi_physical_recv(pgm, recv_buffer, 1);
if (response != 1 || recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_INFO, "%s: Data ACK was expected but not received\n", progname);
return -1;
}
num++;
}
return 0;
}
int updi_link_st_ptr_inc16(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words)
{
/*
def st_ptr_inc16(self, data):
"""
Store a 16-bit word value to the pointer location with pointer post-increment
:param data: data to store
"""
self.logger.debug("ST16 to *ptr++")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_ST | constants.UPDI_PTR_INC |
constants.UPDI_DATA_16, data[0], data[1]])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("ACK error with st_ptr_inc16")
num = 2
while num < len(data):
self.updi_phy.send([data[num], data[num + 1]])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st_ptr_inc16")
num += 2
*/
unsigned char send_buffer[4];
unsigned char recv_buffer[1];
int response;
int num = 2;
avrdude_message(MSG_DEBUG, "%s: ST16 to *ptr++\n", progname);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_ST | UPDI_PTR_INC | UPDI_DATA_16;
send_buffer[2] = buffer[0];
send_buffer[3] = buffer[1];
if (updi_physical_send(pgm, send_buffer, 4) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR_INC16 send operation failed\n", progname);
return -1;
}
response = updi_physical_recv(pgm, recv_buffer, 1);
if (response != 1 || recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_INFO, "%s: ACK was expected but not received\n", progname);
return -1;
}
while (num < words) {
send_buffer[0]=buffer[num];
send_buffer[1]=buffer[num+1];
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR_INC data send operation failed\n", progname);
return -1;
}
response = updi_physical_recv(pgm, recv_buffer, 1);
if (response != 1 || recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_INFO, "%s: Data ACK was expected but not received\n", progname);
return -1;
}
num+=2;
}
return 0;
}
int updi_link_repeat(PROGRAMMER * pgm, uint16_t repeats)
{
/*
def repeat(self, repeats):
"""
Store a value to the repeat counter
:param repeats: number of repeats requested
"""
self.logger.debug("Repeat %d", repeats)
if (repeats - 1) > constants.UPDI_MAX_REPEAT_SIZE:
self.logger.error("Invalid repeat count of %d", repeats)
raise Exception("Invalid repeat count!")
repeats -= 1
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_REPEAT | constants.UPDI_REPEAT_BYTE,
repeats & 0xFF])
*/
unsigned char buffer[3];
avrdude_message(MSG_DEBUG, "%s: Repeat %d\n", progname, repeats);
if ((repeats - 1) > UPDI_MAX_REPEAT_SIZE) {
avrdude_message(MSG_INFO, "%s: Invalid repeat count of %d\n", progname, repeats);
return -1;
}
repeats-=1;
buffer[0] = UPDI_PHY_SYNC;
buffer[1] = UPDI_REPEAT | UPDI_REPEAT_BYTE;
buffer[2] = repeats & 0xFF;
return updi_physical_send(pgm, buffer, 3);
}
int updi_link_read_sib(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size)
{
/*
def read_sib(self):
"""
Read the SIB
"""
return self.updi_phy.sib()
*/
return updi_physical_sib(pgm, buffer, size);
}
int updi_link_key(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size_type, uint16_t size)
{
/*
def key(self, size, key):
"""
Write a key
:param size: size of key (0=64B, 1=128B, 2=256B)
:param key: key value
"""
self.logger.debug("Writing key")
if len(key) != 8 << size:
raise PymcuprogError("Invalid KEY length!")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_KEY | constants.UPDI_KEY_KEY | size])
self.updi_phy.send(list(reversed(list(key))))
*/
unsigned char send_buffer[2];
unsigned char reversed_key[256];
int index;
avrdude_message(MSG_DEBUG, "%s: UPDI writing key\n", progname);
if (size != (8 << size_type)) {
avrdude_message(MSG_INFO, "%s: Invalid key length\n", progname);
return -1;
}
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_KEY | UPDI_KEY_KEY | size_type;
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI key send message failed\n", progname);
return -1;
}
/* reverse key contents */
for (index=0; index<size; index++) {
reversed_key[index] = buffer[size-index-1];
}
return updi_physical_send(pgm, reversed_key, size);
}
int updi_link_ld(PROGRAMMER * pgm, uint32_t address, uint8_t * value)
{
/*
def ld(self, address):
"""
Load a single byte direct from a 24-bit address
:param address: address to load from
:return: value read
"""
self.logger.info("LD from 0x{0:06X}".format(address))
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_LDS | constants.UPDI_ADDRESS_24 | constants.UPDI_DATA_8,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
return self.updi_phy.receive(1)[0]
*/
unsigned char send_buffer[5];
unsigned char recv_buffer[1];
avrdude_message(MSG_DEBUG, "%s: LD from 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_LDS | UPDI_DATA_8 | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_ADDRESS_24 : UPDI_ADDRESS_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_INFO, "%s: LD operation send failed\n", progname);
return -1;
}
if (updi_physical_recv(pgm, recv_buffer, 1) < 0) {
avrdude_message(MSG_INFO, "%s: LD operation recv failed\n", progname);
return -1;
}
* value = recv_buffer[0];
return 0;
}
int updi_link_ld16(PROGRAMMER * pgm, uint32_t address, uint16_t * value)
{
/*
def ld16(self, address):
"""
Load a 16-bit word directly from a 24-bit address
:param address: address to load from
:return: values read
"""
self.logger.info("LD from 0x{0:06X}".format(address))
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_LDS | constants.UPDI_ADDRESS_24 | constants.UPDI_DATA_16,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
return self.updi_phy.receive(2)
*/
unsigned char send_buffer[5];
unsigned char recv_buffer[2];
avrdude_message(MSG_DEBUG, "%s: LD16 from 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_LDS | UPDI_DATA_16 | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_ADDRESS_24 : UPDI_ADDRESS_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_INFO, "%s: LD16 operation send failed\n", progname);
return -1;
}
if (updi_physical_recv(pgm, recv_buffer, 2) < 0) {
avrdude_message(MSG_INFO, "%s: LD16 operation recv failed\n", progname);
return -1;
}
* value = (recv_buffer[0] << 8 | recv_buffer[1]);
return 0;
}
static int updi_link_st_data_phase(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size)
{
/*
def _st_data_phase(self, values):
"""
Performs data phase of transaction:
* receive ACK
* send data
:param values: bytearray of value(s) to send
"""
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st")
self.updi_phy.send(values)
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st")
*/
unsigned char recv_buffer[1];
if (updi_physical_recv(pgm, recv_buffer, 1) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI data phase recv failed on first ACK\n", progname);
return -1;
}
if (recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_INFO, "%s: UPDI data phase expected first ACK\n", progname);
return -1;
}
if (updi_physical_send(pgm, buffer, size) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI data phase send failed\n", progname);
return -1;
}
if (updi_physical_recv(pgm, recv_buffer, 1) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI data phase recv failed on second ACK\n", progname);
return -1;
}
if (recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_INFO, "%s: UPDI data phase expected second ACK\n", progname);
return -1;
}
return 0;
}
int updi_link_st(PROGRAMMER * pgm, uint32_t address, uint8_t value)
{
/*
def st(self, address, value):
"""
Store a single byte value directly to a 24-bit address
:param address: address to write to
:param value: value to write
"""
self.logger.info("ST to 0x{0:06X}".format(address))
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_STS | constants.UPDI_ADDRESS_24 | constants.UPDI_DATA_8,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
return self._st_data_phase([value & 0xFF])
*/
unsigned char send_buffer[5];
avrdude_message(MSG_DEBUG, "%s: ST to 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_STS | UPDI_DATA_8 | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_ADDRESS_24 : UPDI_ADDRESS_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_INFO, "%s: ST operation send failed\n", progname);
return -1;
}
send_buffer[0] = value;
return updi_link_st_data_phase(pgm, send_buffer, 1);
}
int updi_link_st16(PROGRAMMER * pgm, uint32_t address, uint16_t value)
{
/*
def st16(self, address, value):
"""
Store a 16-bit word value directly to a 24-bit address
:param address: address to write to
:param value: value to write
"""
self.logger.info("ST to 0x{0:06X}".format(address))
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_STS | constants.UPDI_ADDRESS_24 | constants.UPDI_DATA_16,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
return self._st_data_phase([value & 0xFF, (value >> 8) & 0xFF])
*/
unsigned char send_buffer[5];
avrdude_message(MSG_DEBUG, "%s: ST16 to 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_STS | UPDI_DATA_16 | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_ADDRESS_24 : UPDI_ADDRESS_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_INFO, "%s: ST16 operation send failed\n", progname);
return -1;
}
send_buffer[0] = value & 0xFF;
send_buffer[1] = (value >> 8) & 0xFF;
return updi_link_st_data_phase(pgm, send_buffer, 2);
}
int updi_link_st_ptr(PROGRAMMER * pgm, uint32_t address)
{
/*
def st_ptr(self, address):
"""
Set the pointer location
:param address: address to write
"""
self.logger.info("ST to ptr")
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_ST | constants.UPDI_PTR_ADDRESS | constants.UPDI_DATA_24,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st_ptr")
*/
unsigned char send_buffer[5];
unsigned char recv_buffer[1];
avrdude_message(MSG_DEBUG, "%s: ST_PTR to 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_STS | UPDI_ST | UPDI_PTR_ADDRESS | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_DATA_24 : UPDI_DATA_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR operation send failed\n", progname);
return -1;
}
if (updi_physical_recv(pgm, recv_buffer, 1) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI ST_PTR recv failed on ACK\n", progname);
return -1;
}
if (recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_INFO, "%s: UPDI ST_PTR expected ACK\n", progname);
return -1;
}
return 0;
}

58
avrdude/updi_link.h Normal file
View File

@ -0,0 +1,58 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#ifndef updi_link_h
#define updi_link_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
int updi_link_open(PROGRAMMER * pgm);
void updi_link_close(PROGRAMMER * pgm);
int updi_link_init(PROGRAMMER * pgm);
int updi_link_ldcs(PROGRAMMER * pgm, uint8_t address, uint8_t * value);
int updi_link_stcs(PROGRAMMER * pgm, uint8_t address, uint8_t value);
int updi_link_ld_ptr_inc(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size);
int updi_link_ld_ptr_inc16(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words);
int updi_link_st_ptr_inc(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size);
int updi_link_st_ptr_inc16(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words);
int updi_link_repeat(PROGRAMMER * pgm, uint16_t repeats);
int updi_link_read_sib(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size);
int updi_link_key(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size_type, uint16_t size);
int updi_link_ld(PROGRAMMER * pgm, uint32_t address, uint8_t * value);
int updi_link_ld16(PROGRAMMER * pgm, uint32_t address, uint16_t * value);
int updi_link_st(PROGRAMMER * pgm, uint32_t address, uint8_t value);
int updi_link_st16(PROGRAMMER * pgm, uint32_t address, uint16_t value);
int updi_link_st_ptr(PROGRAMMER * pgm, uint32_t address);
#ifdef __cplusplus
}
#endif
#endif /* updi_link_h */

1277
avrdude/updi_nvm.c Normal file

File diff suppressed because it is too large Load Diff

51
avrdude/updi_nvm.h Normal file
View File

@ -0,0 +1,51 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#ifndef updi_nvm_h
#define updi_nvm_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
int updi_nvm_chip_erase(PROGRAMMER * pgm, AVRPART * p);
int updi_nvm_erase_flash_page(PROGRAMMER * pgm, AVRPART *p, uint32_t address);
int updi_nvm_erase_eeprom(PROGRAMMER * pgm, AVRPART *p);
int updi_nvm_erase_user_row(PROGRAMMER * pgm, AVRPART *p, uint32_t address, uint16_t size);
int updi_nvm_write_flash(PROGRAMMER * pgm, AVRPART *p, uint32_t address, unsigned char * buffer, uint16_t size);
int updi_nvm_write_user_row(PROGRAMMER * pgm, AVRPART *p, uint32_t address, unsigned char * buffer, uint16_t size);
int updi_nvm_write_eeprom(PROGRAMMER * pgm, AVRPART *p, uint32_t address, unsigned char * buffer, uint16_t size);
int updi_nvm_write_fuse(PROGRAMMER * pgm, AVRPART *p, uint32_t address, uint8_t value);
int updi_nvm_wait_ready(PROGRAMMER * pgm, AVRPART *p);
int updi_nvm_command(PROGRAMMER * pgm, AVRPART *p, uint8_t command);
#ifdef __cplusplus
}
#endif
#endif /* updi_nvm_h */

320
avrdude/updi_readwrite.c Normal file
View File

@ -0,0 +1,320 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#include "ac_cfg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
#include "avrdude.h"
#include "libavrdude.h"
#include "updi_constants.h"
#include "updi_link.h"
#include "updi_readwrite.h"
int updi_read_cs(PROGRAMMER * pgm, uint8_t address, uint8_t * value)
{
/*
def read_cs(self, address):
"""
Read from Control/Status space
:param address: address (index) to read
:return: value read
"""
return self.datalink.ldcs(address)
*/
return updi_link_ldcs(pgm, address, value);
}
int updi_write_cs(PROGRAMMER * pgm, uint8_t address, uint8_t value)
{
/*
def write_cs(self, address, value):
"""
Write to Control/Status space
:param address: address (index) to write
:param value: 8-bit value to write
"""
return self.datalink.stcs(address, value)
*/
return updi_link_stcs(pgm, address, value);
}
int updi_write_key(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size_type, uint16_t size)
{
/*
def write_key(self, size, key):
"""
Write a KEY into UPDI
:param size: size of key to send
:param key: key value
"""
return self.datalink.key(size, key)
*/
return updi_link_key(pgm, buffer, size_type, size);
}
int updi_read_sib(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size)
{
/*
def read_sib(self):
"""
Read the SIB from UPDI
:return: SIB string (bytearray) read
"""
return self.datalink.read_sib()
*/
return updi_link_read_sib(pgm, buffer, size);
}
int updi_read_byte(PROGRAMMER * pgm, uint32_t address, uint8_t * value)
{
/*
def read_byte(self, address):
"""
Read a single byte from UPDI
:param address: address to read from
:return: value read
"""
return self.datalink.ld(address)
*/
return updi_link_ld(pgm, address, value);
}
int updi_write_byte(PROGRAMMER * pgm, uint32_t address, uint8_t value)
{
/*
def write_byte(self, address, value):
"""
Writes a single byte to UPDI
:param address: address to write to
:param value: value to write
"""
return self.datalink.st(address, value)
*/
return updi_link_st(pgm, address, value);
}
int updi_read_data(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size)
{
/*
def read_data(self, address, size):
"""
Reads a number of bytes of data from UPDI
:param address: address to write to
:param size: number of bytes to read
"""
self.logger.debug("Reading %d bytes from 0x%04X", size, address)
# Range check
if size > constants.UPDI_MAX_REPEAT_SIZE:
raise PymcuprogError("Cant read that many bytes in one go")
# Store the address
self.datalink.st_ptr(address)
# Fire up the repeat
if size > 1:
self.datalink.repeat(size)
# Do the read(s)
return self.datalink.ld_ptr_inc(size)
*/
avrdude_message(MSG_DEBUG, "%s: Reading %d bytes from 0x%06X", progname, size, address);
if (size > UPDI_MAX_REPEAT_SIZE) {
avrdude_message(MSG_INFO, "%s: Can't read that many bytes in one go\n", progname);
return -1;
}
if (updi_link_st_ptr(pgm, address) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR operation failed\n", progname);
return -1;
}
if (size > 1) {
if (updi_link_repeat(pgm, size) < 0) {
avrdude_message(MSG_INFO, "%s: Repeat operation failed\n", progname);
return -1;
}
}
return updi_link_ld_ptr_inc(pgm, buffer, size);
}
int updi_write_data(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size)
{
/*
def write_data(self, address, data):
"""
Writes a number of bytes to memory
:param address: address to write to
:param data: data to write
"""
# Special case of 1 byte
if len(data) == 1:
return self.datalink.st(address, data[0])
# Special case of 2 byte
if len(data) == 2:
self.datalink.st(address, data[0])
return self.datalink.st(address + 1, data[1])
# Range check
if len(data) > constants.UPDI_MAX_REPEAT_SIZE:
raise PymcuprogError("Invalid length")
# Store the address
self.datalink.st_ptr(address)
# Fire up the repeat
self.datalink.repeat(len(data))
return self.datalink.st_ptr_inc(data)
*/
if (size == 1) {
return updi_link_st(pgm, address, buffer[0]);
}
if (size == 2) {
if (updi_link_st(pgm, address, buffer[0]) < 0) {
avrdude_message(MSG_INFO, "%s: ST operation failed\n", progname);
return -1;
}
return updi_link_st(pgm, address+1, buffer[1]);
}
if (size > UPDI_MAX_REPEAT_SIZE) {
avrdude_message(MSG_INFO, "%s: Invalid length\n", progname);
return -1;
}
if (updi_link_st_ptr(pgm, address) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR operation failed\n", progname);
return -1;
}
if (updi_link_repeat(pgm, size) < 0) {
avrdude_message(MSG_INFO, "%s: Repeat operation failed\n", progname);
return -1;
}
return updi_link_st_ptr_inc(pgm, buffer, size);
}
int updi_read_data_words(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size)
{
/*
def read_data_words(self, address, words):
"""
Reads a number of words of data from UPDI
:param address: address to write to
:param words: number of words to read
"""
self.logger.debug("Reading %d words from 0x%04X", words, address)
# Range check
if words > constants.UPDI_MAX_REPEAT_SIZE >> 1:
raise PymcuprogError("Cant read that many words in one go")
# Store the address
self.datalink.st_ptr(address)
# Fire up the repeat
if words > 1:
self.datalink.repeat(words)
# Do the read
return self.datalink.ld_ptr_inc16(words)
*/
avrdude_message(MSG_DEBUG, "%s: Reading %d words from 0x%06X", progname, size, address);
if (size > (UPDI_MAX_REPEAT_SIZE >> 1)) {
avrdude_message(MSG_INFO, "%s: Can't read that many words in one go\n", progname);
return -1;
}
if (updi_link_st_ptr(pgm, address) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR operation failed\n", progname);
return -1;
}
if (size > 1) {
if (updi_link_repeat(pgm, size) < 0) {
avrdude_message(MSG_INFO, "%s: Repeat operation failed\n", progname);
return -1;
}
}
return updi_link_ld_ptr_inc16(pgm, buffer, size);
}
int updi_write_data_words(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size)
{
/*
def write_data_words(self, address, data):
"""
Writes a number of words to memory
:param address: address to write to
:param data: data to write
"""
# Special-case of 1 word
if len(data) == 2:
value = data[0] + (data[1] << 8)
return self.datalink.st16(address, value)
# Range check
if len(data) > constants.UPDI_MAX_REPEAT_SIZE << 1:
raise PymcuprogError("Invalid length")
# Store the address
self.datalink.st_ptr(address)
# Fire up the repeat
self.datalink.repeat(len(data) >> 1)
return self.datalink.st_ptr_inc16(data)
*/
if (size == 2) {
return updi_link_st16(pgm, address, buffer[0] + (buffer[1] << 8));
}
if (size > UPDI_MAX_REPEAT_SIZE << 1) {
avrdude_message(MSG_INFO, "%s: Invalid length\n", progname);
return -1;
}
if (updi_link_st_ptr(pgm, address) < 0) {
avrdude_message(MSG_INFO, "%s: ST_PTR operation failed\n", progname);
return -1;
}
if (updi_link_repeat(pgm, size >> 1) < 0) {
avrdude_message(MSG_INFO, "%s: Repeat operation failed\n", progname);
return -1;
}
return updi_link_st_ptr_inc16(pgm, buffer, size);
}

51
avrdude/updi_readwrite.h Normal file
View File

@ -0,0 +1,51 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#ifndef updi_readwrite_h
#define updi_readwrite_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
int updi_read_cs(PROGRAMMER * pgm, uint8_t address, uint8_t * value);
int updi_write_cs(PROGRAMMER * pgm, uint8_t address, uint8_t value);
int updi_write_key(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size_type, uint16_t size);
int updi_read_sib(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size);
int updi_read_byte(PROGRAMMER * pgm, uint32_t address, uint8_t * value);
int updi_write_byte(PROGRAMMER * pgm, uint32_t address, uint8_t value);
int updi_read_data(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size);
int updi_write_data(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size);
int updi_read_data_words(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size);
int updi_write_data_words(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size);
#ifdef __cplusplus
}
#endif
#endif /* updi_readwrite_h */

55
avrdude/updi_state.c Normal file
View File

@ -0,0 +1,55 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#include "ac_cfg.h"
#include "libavrdude.h"
#include "updi_state.h"
updi_sib_info* updi_get_sib_info(PROGRAMMER * pgm)
{
return &((updi_state *)(pgm->cookie))->sib_info;
}
updi_datalink_mode updi_get_datalink_mode(PROGRAMMER * pgm)
{
return ((updi_state *)(pgm->cookie))->datalink_mode;
}
void updi_set_datalink_mode(PROGRAMMER * pgm, updi_datalink_mode mode)
{
((updi_state *)(pgm->cookie))->datalink_mode = mode;
}
updi_nvm_mode updi_get_nvm_mode(PROGRAMMER * pgm)
{
return ((updi_state *)(pgm->cookie))->nvm_mode;
}
void updi_set_nvm_mode(PROGRAMMER * pgm, updi_nvm_mode mode)
{
((updi_state *)(pgm->cookie))->nvm_mode = mode;
}

85
avrdude/updi_state.h Normal file
View File

@ -0,0 +1,85 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2021 Dawid Buchwald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Based on pymcuprog
* See https://github.com/microchip-pic-avr-tools/pymcuprog
*/
#ifndef updi_state_h
#define updi_state_h
#include "libavrdude.h"
typedef enum
{
UPDI_LINK_MODE_16BIT,
UPDI_LINK_MODE_24BIT
} updi_datalink_mode;
typedef enum
{
UPDI_NVM_MODE_V0,
UPDI_NVM_MODE_V2,
UPDI_NVM_MODE_V3
} updi_nvm_mode;
#define SIB_INFO_STRING_LENGTH 32
#define SIB_INFO_FAMILY_LENGTH 8
#define SIB_INFO_NVM_LENGTH 3
#define SIB_INFO_DEBUG_LENGTH 3
#define SIB_INFO_PDI_LENGTH 4
#define SIB_INFO_EXTRA_LENGTH 20
typedef struct
{
unsigned char sib_string[SIB_INFO_STRING_LENGTH+1];
char family_string[SIB_INFO_FAMILY_LENGTH+1];
char nvm_string[SIB_INFO_NVM_LENGTH+1];
char debug_string[SIB_INFO_DEBUG_LENGTH+1];
char pdi_string[SIB_INFO_PDI_LENGTH+1];
char extra_string[SIB_INFO_EXTRA_LENGTH+1];
char nvm_version;
char debug_version;
} updi_sib_info;
typedef struct
{
updi_sib_info sib_info;
updi_datalink_mode datalink_mode;
updi_nvm_mode nvm_mode;
} updi_state;
#ifdef __cplusplus
extern "C" {
#endif
updi_sib_info* updi_get_sib_info(PROGRAMMER * pgm);
updi_datalink_mode updi_get_datalink_mode(PROGRAMMER * pgm);
void updi_set_datalink_mode(PROGRAMMER * pgm, updi_datalink_mode mode);
updi_nvm_mode updi_get_nvm_mode(PROGRAMMER * pgm);
void updi_set_nvm_mode(PROGRAMMER * pgm, updi_nvm_mode mode);
#ifdef __cplusplus
}
#endif
#endif /* updi_state_h */

View File

@ -45,6 +45,7 @@
#include "pickit2.h"
#include "ppi.h"
#include "serbb.h"
#include "serialupdi.h"
#include "stk500.h"
#include "stk500generic.h"
#include "stk500v2.h"
@ -87,6 +88,7 @@ const PROGRAMMER_TYPE programmers_types[] = {
{"par", par_initpgm, par_desc},
{"pickit2", pickit2_initpgm, pickit2_desc},
{"serbb", serbb_initpgm, serbb_desc},
{"serialupdi", serialupdi_initpgm, serialupdi_desc},
{"stk500", stk500_initpgm, stk500_desc},
{"stk500generic", stk500generic_initpgm, stk500generic_desc},
{"stk500v2", stk500v2_initpgm, stk500v2_desc},