Autodetect SPI frequency

- add statemachine for ISP sync & signature read
- autoprobing of SPI frequency
- remove manual SPI frequency selection
- remove NVM code
This commit is contained in:
Olaf Rempel 2014-10-14 21:56:16 +02:00
parent 798fa7fbb1
commit e91782ec65

403
ispprog.c
View File

@ -19,11 +19,9 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/ ***************************************************************************/
#include <avr/io.h> #include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <string.h> #include <string.h>
#include <util/crc16.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
@ -114,21 +112,21 @@
#include <util/delay.h> #include <util/delay.h>
#define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1) #define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1)
/*
* To select SPI SPEED press RESET_IN until LED starts blinking (about 5s)
* press RESET_IN to cycle through SPI speeds (LED frequency changes)
* after timout (about 5s) the LED turns off and the new SPI speed is set
*/
/* F_CPU /4 (1.8432MHz) */ /* F_CPU /4 (1.8432MHz) */
#define SPI_MODE4 ((1<<SPE) | (1<<MSTR)) #define SPI_MODE4 ((1<<SPE) | (1<<MSTR))
/* F_CPU /16 (460.8kHz) */ /* F_CPU /16 (460.8kHz) */
#define SPI_MODE3 ((1<<SPE) | (1<<MSTR) | (1<<SPR1)) #define SPI_MODE3 ((1<<SPE) | (1<<MSTR) | (1<<SPR0))
/* F_CPU /64 (115.2kHz) */ /* F_CPU /64 (115.2kHz) */
#define SPI_MODE2 ((1<<SPE) | (1<<MSTR) | (1<<SPR0)) #define SPI_MODE2 ((1<<SPE) | (1<<MSTR) | (1<<SPR1))
/* F_CPU /128 (57.6kHz) */ /* F_CPU /128 (57.6kHz) */
#define SPI_MODE1 ((1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0)) #define SPI_MODE1 ((1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0))
static const uint8_t spi_modes[4] = { SPI_MODE1, SPI_MODE2, SPI_MODE3, SPI_MODE4 };
#define SPI_SPEED_PROBE 0xFF
static uint8_t spi_speed = SPI_SPEED_PROBE;
#define POLL_00 0x01 /* value 0x00 can not be polled from flash/eeprom */ #define POLL_00 0x01 /* value 0x00 can not be polled from flash/eeprom */
#define POLL_7F 0x02 /* value 0x7F can not be polled from flash/eeprom */ #define POLL_7F 0x02 /* value 0x7F can not be polled from flash/eeprom */
#define POLL_80 0x04 /* value 0x80 can not be polled from flash/eeprom */ #define POLL_80 0x04 /* value 0x80 can not be polled from flash/eeprom */
@ -240,20 +238,19 @@ static const struct _device devices[] PROGMEM = {
// { { 0x1E, 0xA7, 0x01 }, 0xFF, ???, ??? }, /* mega128rfa1 */ // { { 0x1E, 0xA7, 0x01 }, 0xFF, ???, ??? }, /* mega128rfa1 */
}; };
#define EV_NONE 0 #define EV_NONE 0x00
#define EV_STATE_ENTER 1 #define EV_STATE_ENTER 0x01
#define EV_BUTTON_PRESSED 2 #define EV_BUTTON_PRESSED 0x02
#define EV_BUTTON_RELEASED 3 #define EV_BUTTON_RELEASED 0x03
#define EV_TIMEOUT 4 #define EV_TIMEOUT 0x04
#define EV_PROG_ENTER 0x11
#define EV_PROG_LEAVE 0x12
#define STATE_IDLE 0x00 /* nothing */
#define STATE_RESET_SYNC 0x01
#define STATE_RESET_RETRY 0x02
#define STATE_RESET_PROGMODE 0x03
#define STATE_IDLE 0 /* nothing */
#define STATE_PRESSED 1 /* reset_in pressed, generating 50ms isp_reset pulse */
#define STATE_PRESSED2 2 /* reset_in still pressed, isp_reset pulse complete */
#define STATE_SPEED1 3 /* spi speed setting 1 */
#define STATE_SPEED2 4
#define STATE_SPEED3 5
#define STATE_SPEED4 6
#define STATE_NVRAM_STORE 7 /* start nvram_write (internal state) */
#define LED_OFF 0x00 #define LED_OFF 0x00
#define LED_SLOW 0x20 #define LED_SLOW 0x20
@ -304,100 +301,6 @@ static const struct _device devices[] PROGMEM = {
#define CMD_WRITE_FUSE_E_1 0xAC /* not used */ #define CMD_WRITE_FUSE_E_1 0xAC /* not used */
#define CMD_WRITE_FUSE_E_2 0xA4 /* not used */ #define CMD_WRITE_FUSE_E_2 0xA4 /* not used */
struct _nvdata {
uint8_t nvram_size; /* first */
uint8_t spi_mode;
uint16_t nvram_crc; /* last */
};
static uint8_t nvram_write_pos;
static struct _nvdata nvram_data;
static struct _nvdata nvram_eeprom EEMEM;
static const struct _nvdata nvram_defaults PROGMEM = { .spi_mode = SPI_MODE4 };
/* create crc and store nvram data to eeprom */
static void nvram_start_write(void)
{
uint8_t i;
uint16_t crc = 0x0000;
uint8_t *tmp = (uint8_t *)&nvram_data;
#if defined(__AVR_ATmega16__)
if (EECR & (1<<EEWE))
return;
#elif defined(__AVR_ATmega328P__)
if (EECR & (1<<EEPE))
return;
#endif
nvram_data.nvram_size = sizeof(struct _nvdata);
for (i = 0; i < sizeof(struct _nvdata) -2; i++) {
crc = _crc_ccitt_update(crc, *tmp++);
}
nvram_data.nvram_crc = crc;
nvram_write_pos = 0;
EEARL = nvram_write_pos;
EEARH = 0x00;
EEDR = ((uint8_t *)&nvram_data)[nvram_write_pos++];
cli();
#if defined(__AVR_ATmega16__)
EECR |= (1<<EEMWE);
EECR |= (1<<EEWE);
#elif defined(__AVR_ATmega328P__)
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
#endif
EECR |= (1<<EERIE);
sei();
}
/* store nvram data to eeprom */
#if defined(__AVR_ATmega16__)
ISR(EE_RDY_vect)
#elif defined(__AVR_ATmega328P__)
ISR(EE_READY_vect)
#endif
{
if (nvram_write_pos < sizeof(struct _nvdata)) {
EEARL = nvram_write_pos;
EEARH = 0x00;
EEDR = ((uint8_t *)&nvram_data)[nvram_write_pos++];
#if defined(__AVR_ATmega16__)
EECR |= (1<<EEMWE);
EECR |= (1<<EEWE);
#elif defined(__AVR_ATmega328P__)
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
#endif
EECR |= (1<<EERIE);
} else {
EECR &= ~(1<<EERIE);
}
}
/* read nvram from eeprom and check crc */
static void nvram_read(void)
{
uint8_t i;
uint16_t crc = 0x0000;
uint8_t *tmp = (uint8_t *)&nvram_data;
eeprom_read_block(&nvram_data, &nvram_eeprom, sizeof(struct _nvdata));
for (i = 0; i < sizeof(struct _nvdata); i++) {
crc = _crc_ccitt_update(crc, *tmp++);
}
/* if nvram content is invalid, overwrite with defaults */
if ((nvram_data.nvram_size != sizeof(struct _nvdata)) || (crc != 0x0000)) {
memcpy_P(&nvram_data, &nvram_defaults, sizeof(struct _nvdata));
nvram_start_write();
}
}
static volatile uint8_t led_mode = LED_OFF; static volatile uint8_t led_mode = LED_OFF;
@ -510,59 +413,33 @@ static void mem_pagewrite(uint16_t addr)
poll(); poll();
} }
static void reset_statemachine(uint8_t event);
static volatile uint16_t reset_timer = 0x0000;
static volatile uint8_t reset_state;
static void cmdloop(void) __attribute__ ((noreturn)); static void cmdloop(void) __attribute__ ((noreturn));
static void cmdloop(void) static void cmdloop(void)
{ {
static uint8_t page_buf[256]; static uint8_t page_buf[256];
uint16_t addr = 0; uint16_t addr = 0;
/* disable ISP_RESET */
set_reset(1);
while (1) { while (1) {
switch (ser_recv()) { switch (ser_recv()) {
/* Enter programming mode */ /* Enter programming mode */
case 'P': { case 'P': {
uint8_t sync, count = 0x20, retval = '!'; reset_statemachine(EV_PROG_ENTER);
led_mode = LED_ON;
do {
set_reset(1);
_delay_ms(50);
set_reset(0);
_delay_ms(50);
spi_rxtx(CMD_PROG_ENABLE_1); while (1) {
spi_rxtx(CMD_PROG_ENABLE_2); if (reset_state == STATE_IDLE) {
sync = spi_rxtx(0x00); ser_send('!');
spi_rxtx(0x00); break;
} while (sync != CMD_PROG_ENABLE_2 && count--); } else if (reset_state == STATE_RESET_PROGMODE) {
/* device not supported */
memset(&device, 0x00, sizeof(struct _device)); ser_send('\r');
break;
if (sync == CMD_PROG_ENABLE_2) {
uint8_t i;
for (i = 0; i < 3; i++) {
device.sig[i] = mem_read(CMD_READ_SIG_1, (CMD_READ_SIG_2 << 8) | i);
}
for (i = 0; i < ARRAY_SIZE(devices); i++) {
if (memcmp_P(device.sig, devices[i].sig, sizeof(device.sig)) == 0) {
memcpy_P(&device, &devices[i], sizeof(struct _device));
retval = '\r';
break;
}
} }
} }
/* device not supported */
if (retval == '!') {
set_reset(1);
led_mode = LED_OFF;
}
ser_send(retval);
break; break;
} }
@ -687,8 +564,7 @@ static void cmdloop(void)
/* Exit Bootloader */ /* Exit Bootloader */
case 'E': case 'E':
set_reset(1); reset_statemachine(EV_PROG_LEAVE);
led_mode = LED_OFF;
ser_send('\r'); ser_send('\r');
break; break;
@ -905,127 +781,126 @@ static void cmdloop(void)
} }
} }
static uint16_t button_statemachine(uint8_t event) static void reset_statemachine(uint8_t event)
{ {
static uint8_t oldstate; static uint8_t reset_retries;
uint8_t state = oldstate; static uint8_t reset_cause;
uint16_t timer = 0; /* no change */
uint8_t state;
uint8_t oldstate;
uint16_t timer;
cli();
/* copy state, disable timer */
state = reset_state;
timer = reset_timer;
reset_timer = 0x0000;
sei();
do { do {
if (state != oldstate) { oldstate = state;
event = EV_STATE_ENTER;
}
switch (state) { switch (state) {
case STATE_IDLE: case STATE_IDLE:
if (event == EV_STATE_ENTER) { if (event == EV_STATE_ENTER) {
led_mode = LED_OFF; led_mode = LED_OFF;
timer = 0xFFFF; /* stop timer */ timer = 0; /* stop timer */
} else if (event == EV_BUTTON_PRESSED) { /* put device in RUN mode */
state = STATE_PRESSED; set_reset(1);
set_reset(0);
} else if ((event == EV_BUTTON_PRESSED) || (event == EV_PROG_ENTER)) {
memset(&device, 0x00, sizeof(struct _device));
reset_retries = 5;
reset_cause = event;
/* probe SPI speed of device */
if (spi_speed == SPI_SPEED_PROBE) {
spi_speed = 3;
}
state = STATE_RESET_SYNC;
} }
break; break;
case STATE_PRESSED: case STATE_RESET_SYNC:
if (event == EV_STATE_ENTER) { if (event == EV_STATE_ENTER) {
led_mode = LED_ON; led_mode = LED_ON;
timer = 5; /* timeout 50ms (== reset length) */ timer = 5; /* timeout 50ms */
} else if (event == EV_BUTTON_RELEASED) { /* set SPI speed */
state = STATE_IDLE; SPCR = spi_modes[spi_speed];
set_reset(1);
/* put device in ISP mode */
set_reset(0);
} else if (event == EV_TIMEOUT) { } else if (event == EV_TIMEOUT) {
state = STATE_PRESSED2; uint8_t sync;
set_reset(1); spi_rxtx(CMD_PROG_ENABLE_1);
} spi_rxtx(CMD_PROG_ENABLE_2);
break; sync = spi_rxtx(0x00);
spi_rxtx(0x00);
case STATE_PRESSED2: if (sync == CMD_PROG_ENABLE_2) {
if (event == EV_STATE_ENTER) { uint8_t i;
led_mode = LED_OFF; uint8_t sig[3];
timer = 500; /* timeout in 5s */
} else if (event == EV_BUTTON_RELEASED) { for (i = 0; i < 3; i++) {
state = STATE_IDLE; sig[i] = mem_read(CMD_READ_SIG_1, (CMD_READ_SIG_2 << 8) | i);
}
} else if (event == EV_TIMEOUT) { for (i = 0; i < ARRAY_SIZE(devices); i++) {
switch (SPCR) { if (memcmp_P(sig, devices[i].sig, sizeof(device.sig)) == 0) {
case SPI_MODE1: memcpy_P(&device, &devices[i], sizeof(struct _device));
state = STATE_SPEED1; break;
break; }
}
case SPI_MODE2: state = (reset_cause == EV_PROG_ENTER) ? STATE_RESET_PROGMODE
state = STATE_SPEED2; : STATE_IDLE;
break;
case SPI_MODE3: } else {
state = STATE_SPEED3; state = STATE_RESET_RETRY;
break;
default:
case SPI_MODE4:
state = STATE_SPEED4;
break;
} }
} }
break; break;
case STATE_SPEED1: case STATE_RESET_RETRY:
if (event == EV_STATE_ENTER) { if (event == EV_STATE_ENTER) {
led_mode = LED_SPEED1; led_mode = LED_OFF;
timer = 500; /* timeout in 5s */ timer = 5; /* timeout 50ms */
} else if (event == EV_BUTTON_PRESSED) { /* put device in RUN mode */
state = STATE_SPEED2; set_reset(1);
} else if (event == EV_TIMEOUT) { } else if (event == EV_TIMEOUT) {
state = STATE_NVRAM_STORE; reset_retries--;
SPCR = SPI_MODE1; if (reset_retries > 0) {
/* try lower frequency */
if (spi_speed > 0) {
spi_speed--;
}
state = STATE_RESET_SYNC;
} else {
/* got no sync, probe speed again next time */
spi_speed = SPI_SPEED_PROBE;
state = STATE_IDLE;
}
} }
break; break;
case STATE_SPEED2: case STATE_RESET_PROGMODE:
if (event == EV_STATE_ENTER) { if (event == EV_STATE_ENTER) {
led_mode = LED_SPEED2;
timer = 500; /* timeout in 5s */ } else if (event == EV_PROG_LEAVE) {
/* was in prog mode (osc changed?), probe speed next time */
spi_speed = SPI_SPEED_PROBE;
state = STATE_IDLE;
} else if (event == EV_BUTTON_PRESSED) { } else if (event == EV_BUTTON_PRESSED) {
state = STATE_SPEED3; state = STATE_IDLE;
} else if (event == EV_TIMEOUT) {
state = STATE_NVRAM_STORE;
SPCR = SPI_MODE2;
}
break;
case STATE_SPEED3:
if (event == EV_STATE_ENTER) {
led_mode = LED_SPEED3;
timer = 500; /* timeout in 5s */
} else if (event == EV_BUTTON_PRESSED) {
state = STATE_SPEED4;
} else if (event == EV_TIMEOUT) {
state = STATE_NVRAM_STORE;
SPCR = SPI_MODE3;
}
break;
case STATE_SPEED4:
if (event == EV_STATE_ENTER) {
led_mode = LED_SPEED4;
timer = 500; /* timeout in 5s */
} else if (event == EV_BUTTON_PRESSED) {
state = STATE_SPEED1;
} else if (event == EV_TIMEOUT) {
state = STATE_NVRAM_STORE;
SPCR = SPI_MODE4;
} }
break; break;
@ -1034,19 +909,16 @@ static uint16_t button_statemachine(uint8_t event)
break; break;
} }
if (state == STATE_NVRAM_STORE) { event = (oldstate != state) ? EV_STATE_ENTER
state = STATE_IDLE; : EV_NONE;
nvram_data.spi_mode = SPCR;
nvram_start_write();
}
if (event == EV_STATE_ENTER) { } while (oldstate != state);
oldstate = state;
}
} while (state != oldstate); cli();
/* copy state back */
return timer; reset_timer = timer;
reset_state = state;
sei();
} }
/* time keeping */ /* time keeping */
@ -1071,22 +943,15 @@ ISR(TIMER0_OVF_vect)
} }
} }
static uint16_t timer; if (reset_timer) {
if (timer) { reset_timer--;
timer--; if (reset_timer == 0) {
if (timer == 0) {
event = EV_TIMEOUT; event = EV_TIMEOUT;
} }
} }
if (event != EV_NONE) { if (event != EV_NONE) {
uint16_t new_timer = button_statemachine(event); reset_statemachine(event);
if (new_timer == 0xFFFF) {
timer = 0;
} else if (new_timer > 0) {
timer = new_timer;
}
} }
/* update LED */ /* update LED */
@ -1141,11 +1006,8 @@ int main(void)
UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
#endif #endif
/* read stored parameters */
nvram_read();
/* enable SPI master mode */ /* enable SPI master mode */
SPCR = nvram_data.spi_mode; SPCR = SPI_MODE4;
#if defined(__AVR_ATmega16__) #if defined(__AVR_ATmega16__)
/* timer0, FCPU/1024, overflow interrupt */ /* timer0, FCPU/1024, overflow interrupt */
@ -1156,6 +1018,9 @@ int main(void)
TIMSK0 = (1<<TOIE0); TIMSK0 = (1<<TOIE0);
#endif #endif
/* init statemachine */
reset_statemachine(EV_STATE_ENTER);
sei(); sei();
cmdloop(); cmdloop();