Browse Source

Add twiboot bridge

master
Olaf Rempel 1 month ago
parent
commit
144016f65d
7 changed files with 683 additions and 5 deletions
  1. +1
    -1
      display.c
  2. +318
    -4
      ispprog.c
  3. +3
    -0
      target.h
  4. +286
    -0
      twi_master.c
  5. +62
    -0
      twi_master.h
  6. +12
    -0
      uart.c
  7. +1
    -0
      uart.h

+ 1
- 1
display.c View File

@@ -23,7 +23,7 @@

#if (USE_DISPLAY)
static display_mode_t m_mode = DISPLAY_MODE_OFF;
static char m_buffer[24];
static char m_buffer[32];
static uint8_t m_buffer_length = 0;
static uint8_t m_buffer_pos = 0;



+ 318
- 4
ispprog.c View File

@@ -26,8 +26,11 @@
#include "display.h"
#include "spi_isp.h"
#include "target.h"
#include "twi_master.h"
#include "uart.h"

#define MIN(a,b) (((a) < (b)) ? (a) : (b))

#define TIMER_IRQFREQ_MS 10

/* convert milliseconds to timer ticks */
@@ -41,12 +44,14 @@
#define EV_TIMEOUT 0x08
#define EV_PROG_ENTER 0x10
#define EV_PROG_LEAVE 0x20
#define EV_PROG_ENTER_TWI 0x40

#define STATE_IDLE 0x00 /* nothing */
#define STATE_RESET_SYNC 0x01
#define STATE_RESET_RETRY 0x02
#define STATE_RESET_PROGMODE 0x03

#define STATE_TWI_CHECK_BL 0x04
#define STATE_TWI_PROGMODE 0x05

#define LED_OFF 0x00
#define LED_SLOW 0x20
@@ -63,6 +68,11 @@ static uint8_t m_page_buf[256];
static avr_device_t m_device;
static uint16_t m_address = 0x0000;

#if (USE_TWI_SUPPORT)
static twi_chipinfo_t m_twi_chipinfo;
static uint8_t m_twi_address;
#endif /* (USE_TWI_SUPPORT) */


static void reset_statemachine(uint8_t events)
{
@@ -105,12 +115,20 @@ static void reset_statemachine(uint8_t events)
timer = TIMER_MSEC2IRQCNT(0);

spi_init(0);

#if (USE_TWI_SUPPORT)
twi_init(0);
#endif
/* put device in RUN mode */
RESET_INACTIVE();
m_led_mode = LED_OFF;
}
else if (events & (EV_BUTTON_PRESSED | EV_PROG_ENTER))
else if ((events & EV_PROG_ENTER) ||
#if (USE_TWI_SUPPORT)
((events & EV_BUTTON_PRESSED) && (m_twi_address == 0x00))
#else
(events & EV_BUTTON_PRESSED)
#endif /* (USE_TWI_SUPPORT) */
)
{
reset_cause = events;
events &= ~(EV_BUTTON_PRESSED | EV_PROG_ENTER);
@@ -122,6 +140,29 @@ static void reset_statemachine(uint8_t events)

m_state = STATE_RESET_SYNC;
}
#if (USE_TWI_SUPPORT)
else if ((events & EV_PROG_ENTER_TWI) ||
((events & EV_BUTTON_PRESSED) && (m_twi_address != 0x00))
)
{
uint8_t result;

reset_cause = events;
events &= ~(EV_BUTTON_PRESSED | EV_PROG_ENTER_TWI);

reset_retries = 5;

twi_init(1);
result = twi_switch_application(m_twi_address, BOOTTYPE_BOOTLOADER);
if (result == TWI_ERROR)
{
/* no response from target, do normal reset */
RESET_ACTIVE();
}

m_state = STATE_TWI_CHECK_BL;
}
#endif /* (USE_TWI_SUPPORT) */
break;

case STATE_RESET_SYNC:
@@ -204,6 +245,101 @@ static void reset_statemachine(uint8_t events)
}
break;

#if (USE_TWI_SUPPORT)
case STATE_TWI_CHECK_BL:
if (events & EV_STATE_ENTER)
{
events &= ~(EV_STATE_ENTER);

timer = TIMER_MSEC2IRQCNT(10);
}
else if (events & EV_TIMEOUT)
{
uint8_t result;

events &= ~(EV_TIMEOUT);

/* put target in RUN mode */
RESET_INACTIVE();
m_led_mode = LED_ON;

result = twi_read_chipinfo(m_twi_address, &m_twi_chipinfo);
if (result == TWI_SUCCESS)
{
#if (USE_DISPLAY)
char twi_version[16 +1];

twi_read_version(m_twi_address, twi_version,
sizeof(twi_version) -1);
twi_version[16] = '\0';

display_show_string(twi_version, 0);

avrdevice_get_by_signature(&m_device, m_twi_chipinfo.sig);
if (m_device.name[0] != '\0')
{
display_show_string(" ", 1);
display_show_string(m_device.name, 1);
}
else
{
display_show_string(" 0X", 1);
display_show_hex(m_twi_chipinfo.sig[0], 1);
display_show_hex(m_twi_chipinfo.sig[1], 1);
display_show_hex(m_twi_chipinfo.sig[2], 1);
}

display_set_mode(DISPLAY_MODE_SCROLL_ONCE);
#endif /* (USE_DISPLAY) */

m_state = STATE_TWI_PROGMODE;
}
else
{
reset_retries--;
if (reset_retries > 0)
{
timer = TIMER_MSEC2IRQCNT(10);
}
else
{
#if (USE_DISPLAY)
display_show_string("0x", 0);
display_show_hex(m_twi_address, 1);
display_show_string(":NAK", 1);
display_set_mode(DISPLAY_MODE_SCROLL_ONCE);
#endif /* (USE_DISPLAY) */

m_state = STATE_IDLE;
}
}
}
break;

case STATE_TWI_PROGMODE:
if (events & EV_STATE_ENTER)
{
events &= ~(EV_STATE_ENTER);

if (reset_cause == EV_BUTTON_PRESSED)
{
m_state = STATE_IDLE;
}
}
else if (events & EV_PROG_LEAVE)
{
events &= ~(EV_PROG_LEAVE);

m_state = STATE_IDLE;
}

if (m_state == STATE_IDLE)
{
twi_switch_application(m_twi_address, BOOTTYPE_APPLICATION);
}
break;
#endif /* (USE_TWI_SUPPORT) */

default:
m_state = STATE_IDLE;
break;
@@ -380,6 +516,7 @@ static void cmd_handler_isp(uint8_t cmd)
size |= uart_recv();
type = uart_recv();

size = MIN(size, sizeof(m_page_buf));
uart_recv_buf(m_page_buf, size);

if (type == 'F')
@@ -487,6 +624,124 @@ static void cmd_handler_isp(uint8_t cmd)
} /* cmd_handler_isp */


#if (USE_TWI_SUPPORT)
static void cmd_handler_twi(uint8_t cmd)
{
switch (cmd)
{
/* Enter programming mode */
case 'P':
reset_statemachine_wait(EV_PROG_ENTER_TWI);
uart_send((m_state == STATE_TWI_PROGMODE) ? '\r' : '!');
break;

/* Chip erase */
case 'e':
uart_send('\r');
break;

/* Read signature bytes */
case 's':
uart_send(m_twi_chipinfo.sig[2]);
uart_send(m_twi_chipinfo.sig[1]);
uart_send(m_twi_chipinfo.sig[0]);
break;

/* Block Write */
case 'B':
{
uint16_t write_pos = 0;
uint16_t size;
uint8_t type;

m_led_mode = LED_FAST;

size = uart_recv() << 8;
size |= uart_recv();
type = uart_recv();

size = MIN(size, sizeof(m_page_buf));
uart_recv_buf(m_page_buf, size);

memset(m_page_buf + size, 0xFF, sizeof(m_page_buf) - size);

while (write_pos < size)
{
if (type == 'F')
{
twi_write_memory(m_twi_address, MEMTYPE_FLASH,
(m_address << 1),
m_page_buf + write_pos,
m_twi_chipinfo.page_size);

/* when accessing flash, m_address is a word address */
m_address += (m_twi_chipinfo.page_size >> 1);
write_pos += m_twi_chipinfo.page_size;
}
else
{
uint8_t write_size;

write_size = MIN(size, m_twi_chipinfo.page_size);

twi_write_memory(m_twi_address, MEMTYPE_EEPROM,
m_address,
m_page_buf + write_pos,
write_size);

/* when accessing eeprom, m_address is a byte address */
m_address += write_size;
write_pos += write_size;
}
}

uart_send('\r');
break;
}

/* Block Read */
case 'g':
{
uint16_t size;
uint8_t type;

m_led_mode = LED_SLOW;

size = uart_recv() << 8;
size |= uart_recv();
type = uart_recv();

size = MIN(size, sizeof(m_page_buf));

if (type == 'F')
{
twi_read_memory(m_twi_address, MEMTYPE_FLASH,
(m_address << 1),
m_page_buf, size);

m_address += (size >> 1);
}
else
{
twi_read_memory(m_twi_address, MEMTYPE_EEPROM,
m_address,
m_page_buf, size);

m_address += size;
}

uart_send_buf(m_page_buf, size);
break;
}

default:
uart_send('?');
break;
}
} /* cmd_handler_twi */
#endif /* (USE_TWI_SUPPORT) */


static void cmdloop(void) __attribute__ ((noreturn));
static void cmdloop(void)
{
@@ -596,12 +851,67 @@ static void cmdloop(void)
uart_send(sizeof(m_page_buf) & 0xFF);
break;

#if (USE_TWI_SUPPORT)
case 'I':
m_twi_address = uart_recv() & 0x7F;

if (m_twi_address != 0x00)
{
reset_statemachine_wait(EV_PROG_ENTER_TWI);
if (m_state == STATE_TWI_PROGMODE)
{
uart_send('\r');
}
else
{
m_twi_address = 0x00;
uart_send('!');
}
}
else
{
uart_send('\r');
}
break;

case 'i':
{
uint8_t twi_addr;
uint8_t write_size;
uint8_t read_size;
uint8_t result;

twi_addr = uart_recv();
write_size = uart_recv();
read_size = uart_recv();

uart_recv_buf(m_page_buf, write_size);

result = twi_generic(twi_addr,
m_page_buf, write_size,
m_page_buf, read_size);

uart_send_buf(m_page_buf, read_size);

uart_send((result == TWI_SUCCESS) ? '\r' : '!');
}
#endif /* (USE_TWI_SUPPORT) */

/* ESC */
case 0x1B:
break;

default:
cmd_handler_isp(cmd);
#if (USE_TWI_SUPPORT)
if (m_twi_address != 0x00)
{
cmd_handler_twi(cmd);
}
else
#endif /* (USE_TWI_SUPPORT) */
{
cmd_handler_isp(cmd);
}
break;
}
}
@@ -683,6 +993,10 @@ int main(void)

spi_init(0);

#if (USE_TWI_SUPPORT)
twi_init(0);
#endif

TIMER_INIT();

/* init statemachine */


+ 3
- 0
target.h View File

@@ -34,6 +34,7 @@
#define ISP_CHECK() (PIND & (1<<RESET_IN))

#define USE_DISPLAY 0
#define USE_TWI_SUPPORT 0

#define TIMER_DIVISOR 1024
#define TIMER_INIT() { /* timer0, FCPU/1024, overflow interrupt */ \
@@ -95,6 +96,8 @@
#define DISP_D5 PORTD6
#define DISP_D6 PORTD7

#define USE_TWI_SUPPORT 1

#define TIMER_DIVISOR 1024
#define TIMER_INIT() { /* timer0, FCPU/1024, overflow interrupt */ \
TCCR0B = (1<<CS02) | (1<<CS00); \


+ 286
- 0
twi_master.c View File

@@ -0,0 +1,286 @@
/***************************************************************************
* Copyright (C) 2006 - 2020 by Olaf Rempel *
* razzor AT kopf MINUS tisch DOT de *
* *
* 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; version 2 of the License, *
* *
* 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. *
***************************************************************************/
#include <avr/io.h>
#include <string.h>

#include "target.h"
#include "twi_master.h"

#if (USE_TWI_SUPPORT)

#define TWI_SLA_W(addr) (addr << 1)
#define TWI_SLA_R(addr) ((addr << 1) | 0x01)


/* ***********************************************************************
* twi_start
* *********************************************************************** */
static uint8_t twi_start(void)
{
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
loop_until_bit_is_set(TWCR, TWINT);

switch (TWSR & 0xF8)
{
case 0x08: /* START transmitted */
case 0x10: /* repeated START transmitted */
return TWI_SUCCESS;

default:
return TWI_ERROR;
}
} /* twi_start */


/* ***********************************************************************
* twi_stop
* *********************************************************************** */
static void twi_stop(void)
{
TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
} /* twi_stop */


/* ***********************************************************************
* twi_master_tx
* *********************************************************************** */
static uint8_t twi_master_tx(uint8_t value)
{
TWDR = value;
TWCR = (1<<TWINT) | (1<<TWEN);
loop_until_bit_is_set(TWCR, TWINT);

switch (TWSR & 0xF8)
{
case 0x18: /* SLA+W transmitted, ACK received */
case 0x28: /* Data transmitted, ACK received */
case 0x40: /* SLA+R transmitted, ACK received */
return TWI_SUCCESS;

default:
return TWI_ERROR;
}
} /* twi_master_tx */


/* ***********************************************************************
* twi_master_rx
* *********************************************************************** */
static uint8_t twi_master_rx(uint8_t * p_value, uint8_t ack)
{
TWCR = (1<<TWINT) | (1<<TWEN) | ((ack) ? (1<<TWEA) : 0x00);
loop_until_bit_is_set(TWCR, TWINT);
*p_value = TWDR;

switch (TWSR & 0xF8)
{
case 0x50: /* Data received, ACK returned */
case 0x58: /* Data received, NAK returned */
return TWI_SUCCESS;

default:
return TWI_ERROR;
}
} /* twi_master_rx */


/* ***********************************************************************
* twi_master_start
* *********************************************************************** */
static uint8_t twi_master_start(uint8_t twi_addr)
{
if (twi_start() == TWI_SUCCESS)
{
if (twi_master_tx(twi_addr) == TWI_SUCCESS)
{
return TWI_SUCCESS;
}
}

twi_stop();
return TWI_ERROR;
} /* twi_master_start */


/* ***********************************************************************
* twi_generic
* *********************************************************************** */
uint8_t twi_generic(uint8_t twi_addr,
const uint8_t * p_wr_data, uint16_t write_size,
uint8_t * p_rd_data, uint16_t read_size)
{
uint8_t result = TWI_ERROR;

if (write_size > 0)
{
result = twi_master_start(TWI_SLA_W(twi_addr));
if (result == TWI_SUCCESS)
{
uint16_t i;

for (i = 0; i < write_size; i++)
{
result = twi_master_tx(*p_wr_data++);
if (result != TWI_SUCCESS)
{
break;
}
}
}
}

if ((read_size > 0) &&
(result == TWI_SUCCESS)
)
{
result = twi_master_start(TWI_SLA_R(twi_addr));
if (result == TWI_SUCCESS)
{
uint16_t i;

for (i = 0; i < read_size; i++)
{
uint8_t ack;

ack = (i != (read_size -1));
result = twi_master_rx(p_rd_data++, ack);
if (result != TWI_SUCCESS)
{
break;
}
}
}
}

twi_stop();
return result;
} /* twi_generic */


/* ***********************************************************************
* twi_switch_application
* *********************************************************************** */
uint8_t twi_switch_application(uint8_t twi_addr, uint8_t app)
{
uint8_t cmd[2] = { CMD_SWITCH_APPLICATION, app };

return twi_generic(twi_addr, cmd, sizeof(cmd), NULL, 0);
} /* twi_switch_application */


/* ***********************************************************************
* twi_read_version
* *********************************************************************** */
uint8_t twi_read_version(uint8_t twi_addr, char * p_version,
uint8_t version_length)
{
uint8_t cmd[1] = { CMD_READ_VERSION };

return twi_generic(twi_addr, cmd, sizeof(cmd),
(uint8_t *)p_version, version_length);
} /* twi_read_version */


/* ***********************************************************************
* twi_read_chipinfo
* *********************************************************************** */
uint8_t twi_read_chipinfo(uint8_t twi_addr, twi_chipinfo_t * p_chipinfo)
{
uint8_t cmd[4] = { CMD_READ_MEMORY, MEMTYPE_CHIPINFO, 0x00, 0x00 };

return twi_generic(twi_addr, cmd, sizeof(cmd),
(uint8_t *)p_chipinfo, sizeof(twi_chipinfo_t));
} /* twi_read_chipinfo */


/* ***********************************************************************
* twi_read_memory
* *********************************************************************** */
uint8_t twi_read_memory(uint8_t twi_addr, uint8_t memory_type, uint16_t memory_addr,
uint8_t * p_data, uint16_t data_length)
{
uint8_t cmd[4] = { CMD_READ_MEMORY, memory_type,
(memory_addr >> 8) & 0xFF,
(memory_addr & 0xFF) };

return twi_generic(twi_addr, cmd, sizeof(cmd), p_data, data_length);
} /* twi_read_memory */


/* ***********************************************************************
* twi_write_memory
* *********************************************************************** */
uint8_t twi_write_memory(uint8_t twi_addr, uint8_t memory_type, uint16_t memory_addr,
const uint8_t * p_data, uint16_t data_length)
{
uint8_t cmd[4] = { CMD_WRITE_MEMORY, memory_type,
(memory_addr >> 8) & 0xFF,
(memory_addr & 0xFF) };
uint8_t result;

result = twi_master_start(TWI_SLA_W(twi_addr));
if (result == TWI_SUCCESS)
{
uint16_t i;

for (i = 0; i < sizeof(cmd); i++)
{
result = twi_master_tx(cmd[i]);
if (result != TWI_SUCCESS)
{
break;
}
}
}

if (result == TWI_SUCCESS)
{
uint16_t i;

for (i = 0; i < data_length; i++)
{
result = twi_master_tx(*p_data++);
if (result != TWI_SUCCESS)
{
break;
}
}
}

twi_stop();
return result;
} /* twi_read_memory */


/* ***********************************************************************
* twi_init
* *********************************************************************** */
void twi_init(uint8_t enable)
{
if (enable)
{
TWBR = ((F_CPU / 100000) -16) / 2;
TWCR = (1<<TWSTO) | (1<<TWEN);
}
else
{
TWCR = 0x00;
}
} /* twi_init */
#endif /* (USE_TWI_SUPPORT) */

+ 62
- 0
twi_master.h View File

@@ -0,0 +1,62 @@
#ifndef TWI_MASTER_H_
#define TWI_MASTER_H_

#include <stdint.h>

/* *********************************************************************** */

/* SLA+R */
#define CMD_WAIT 0x00
#define CMD_READ_VERSION 0x01
#define CMD_READ_MEMORY 0x02

/* SLA+W */
#define CMD_SWITCH_APPLICATION CMD_READ_VERSION
#define CMD_WRITE_MEMORY CMD_READ_MEMORY

/* CMD_SWITCH_APPLICATION parameter */
#define BOOTTYPE_BOOTLOADER 0x00
#define BOOTTYPE_APPLICATION 0x80

/* CMD_{READ|WRITE}_* parameter */
#define MEMTYPE_CHIPINFO 0x00
#define MEMTYPE_FLASH 0x01
#define MEMTYPE_EEPROM 0x02

#define TWI_SUCCESS 0x00
#define TWI_ERROR 0x01

typedef struct twi_chipinfo_s
{
uint8_t sig[3];
uint8_t page_size;
uint16_t flash_size;
uint16_t eeprom_size;
} twi_chipinfo_t;

/* *********************************************************************** */

uint8_t twi_generic (uint8_t twi_addr,
const uint8_t * p_wr_data, uint16_t write_size,
uint8_t * p_rd_data, uint16_t read_size);

uint8_t twi_switch_application (uint8_t addr, uint8_t app);

uint8_t twi_read_version (uint8_t addr, char * p_version,
uint8_t version_length);

uint8_t twi_read_chipinfo (uint8_t addr, twi_chipinfo_t * p_chipinfo);

uint8_t twi_read_memory (uint8_t twi_addr, uint8_t memory_type,
uint16_t memory_addr,
uint8_t * p_data, uint16_t data_length);

uint8_t twi_write_memory (uint8_t twi_addr, uint8_t memory_type,
uint16_t memory_addr,
const uint8_t * p_data, uint16_t data_length);

void twi_init (uint8_t enable);

/* *********************************************************************** */

#endif /* TWI_MASTER_H_ */

+ 12
- 0
uart.c View File

@@ -67,6 +67,18 @@ uint8_t uart_rx_ready(void)


/* ***********************************************************************
* uart_send_buf
* *********************************************************************** */
void uart_send_buf(const uint8_t * p_data, uint16_t data_length)
{
while (data_length--)
{
uart_send(*p_data++);
}
} /* uart_send_buf */


/* ***********************************************************************
* uart_recv_buf
* *********************************************************************** */
void uart_recv_buf(uint8_t * p_data, uint16_t data_length)


+ 1
- 0
uart.h View File

@@ -9,6 +9,7 @@ void uart_send (uint8_t data);
uint8_t uart_recv (void);
uint8_t uart_rx_ready (void);

void uart_send_buf (const uint8_t * p_data, uint16_t data_length);
void uart_recv_buf (uint8_t * p_data, uint16_t data_length);

void uart_init (void);


Loading…
Cancel
Save