Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
bdmtrionic.cpp
- Committer:
- Just4pLeisure
- Date:
- 2013-09-11
- Revision:
- 4:682d96ff6d79
- Parent:
- 2:bf3a2b29259a
- Child:
- 5:1775b4b13232
File content as of revision 4:682d96ff6d79:
/*******************************************************************************
bdmtrionic.cpp
(c) 2010 by Sophie Dexter
General purpose BDM functions for Just4Trionic by Just4pLeisure
A derivative work based on:
//-----------------------------------------------------------------------------
// CAN/BDM adapter firmware
// (C) Janis Silins, 2010
// $id$
//-----------------------------------------------------------------------------
********************************************************************************
WARNING: Use at your own risk, sadly this software comes with no guarantees.
This software is provided 'free' and in good faith, but the author does not
accept liability for any damage arising from its use.
*******************************************************************************/
#include "bdmtrionic.h"
// structure for command address/value pairs
struct mempair_t {
uint32_t addr; ///< target address
uint16_t val; ///< word value
};
// word write algorithm (29Fxxx)
static const struct mempair_t am29_write [] = {
{0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0xa0a0},
};
// chip erase algorithms
static const struct mempair_t am29_erase [] = {
{0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x8080},
{0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x1010}
};
// reset algorithms
//static const struct mempair_t am29_reset = {0xfffe, 0xf0f0};
static const struct mempair_t am29_reset [] = {
{0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0xf0f0},
};
// chip id algorithms
static const struct mempair_t am29_id [] = {
{0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x9090},
};
// ;-)
static const struct mempair_t flash_tag [] = {
{0x7fe00, 0xFF4A}, {0x7fe02, 0x7573}, {0x7fe04, 0x7434}, {0x7fe06, 0x704C},
{0x7fe08, 0x6569}, {0x7fe0a, 0x7375}, {0x7fe0c, 0x7265}, {0x7fe0e, 0x3B29},
};
// local functions
bool reset_am29(void);
bool erase_am29();
bool flash_am29(const uint32_t* addr, uint16_t value);
bool reset_am28(void);
bool erase_am28(const uint32_t* start_addr, const uint32_t* end_addr);
bool flash_am28(const uint32_t* addr, uint16_t value);
bool get_flash_id(uint8_t* make, uint8_t* type);
//-----------------------------------------------------------------------------
/**
Dumps contents of a memory block from [start_addr] up to, but not including,
the [end_addr] as long words (word-aligned addresses). MCU must be in
background mode. The operation interrupts if the break character is
received.
@param start_addr block start address
@param end_addr block end address
@return status flag
*/
uint8_t dump_flash(const uint32_t* start_addr, const uint32_t* end_addr)
{
// check parametres
if (*start_addr > *end_addr) {
return TERM_ERR;
}
// dump memory contents
uint32_t curr_addr = *start_addr;
uint32_t value;
while ((curr_addr < *end_addr) && (pc.getc() != TERM_BREAK)) {
// read long word
if (curr_addr > *start_addr) {
if (memdump_long(&value) != TERM_OK) {
return TERM_ERR;
}
} else {
if (memread_long(&value, &curr_addr) != TERM_OK) {
return TERM_ERR;
}
}
// send memory value to host
printf("%08X", value);
printf("\r\n");
// add the terminating character
if (curr_addr < *end_addr - 4) {
pc.putc(TERM_OK);
// light up the activity LED
ACTIVITYLEDON;
}
curr_addr += 4;
}
return TERM_OK;
}
//-----------------------------------------------------------------------------
/**
Dumps the contents of a T5 ECU to a BIN file on the mbed 'disk'
from [start_addr] up to, but not including, the [end_addr].
MCU must be in background mode.
@param start_addr block start address
@param end_addr block end address
@return status flag
*/
uint8_t dump_trionic()
{
// Configure the MC68332 register values to prepare for flashing
printf("I am trying to discover what type of Trionic ECU I am connected to...\r\n");
prep_t5_do();
// Work out what type of FLASH chips we want to make a dump file for
uint8_t make;
uint8_t type;
get_flash_id(&make, &type);
// set up chip-specific functions
bool (*reset_func)();
uint32_t flash_size;
switch (type) {
case AMD29BL802C:
printf("I have found AMD29BL802C type FLASH chips; I must be connected to a T8 ECU :-)\r\n");
reset_func = &reset_am29;
flash_size = T8FLASHSIZE;
break;
case AMD29F400B:
case AMD29F400T:
printf("I have found AMD29F400 type FLASH chips; I must be connected to a T7 ECU :-)\r\n");
reset_func = &reset_am29;
flash_size = T7FLASHSIZE;
break;
case AMD29F010:
printf("I have found AMD29F010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n");
reset_func = &reset_am29;
flash_size = T55FLASHSIZE;
break;
case AMD28F010:
case INTEL28F010:
printf("I have found 28F010 type FLASH chips; I must be connected to a T5.5 ECU :-)\r\n");
reset_func = &reset_am28;
flash_size = T55FLASHSIZE;
break;
case AMD28F512:
case INTEL28F512:
printf("I have found 28F512 type FLASH chips; I must be connected to a T5.2 ECU :-)\r\n");
reset_func = &reset_am28;
flash_size = T52FLASHSIZE;
break;
default:
// unknown flash type
printf("I could not work out what FLASH chips or TRIONIC ECU I am connected to :-(\r\n");
return TERM_ERR;
}
// reset the FLASH chips
if (!reset_func()) return TERM_ERR;
printf("Creating FLASH dump file...\r\n");
FILE *fp = fopen("/local/original.bin", "w"); // Open "original.bin" on the local file system for writing
if (!fp) {
perror ("The following error occured");
return TERM_ERR;
}
// dump memory contents
uint32_t addr = 0x00;
uint32_t long_value;
// setup start address to dump from
if (memread_long_cmd(&addr) != TERM_OK) return TERM_ERR;
timer.reset();
timer.start();
printf(" 0.00 %% complete.\r");
while (addr < flash_size) {
uint16_t byte_count = 0;
while (byte_count < FILE_BUF_LENGTH) {
// get long word
if (memget_long(&long_value) != TERM_OK) return TERM_ERR;
addr += 4;
// send memory value to file_buffer before saving to mbed 'disk'
file_buffer[byte_count] = ((uint8_t)(long_value >> 24));
file_buffer[byte_count+1] = ((uint8_t)(long_value >> 16));
file_buffer[byte_count+2] = ((uint8_t)(long_value >> 8));
file_buffer[byte_count+3] = ((uint8_t)long_value);
byte_count +=4;
// make the activity led twinkle
ACTIVITYLEDON;
}
fwrite(file_buffer, 1, FILE_BUF_LENGTH, fp);
if (ferror (fp)) {
fclose (fp);
printf ("Error writing to the FLASH BIN file.\r\n");
return TERM_ERR;
}
printf("%6.2f\r", 100*(float)addr/(float)flash_size );
}
printf("\n");
// should 'clear' the BDM connection here but bdm_clear won't compile from here
// instead do a memread (or anything really) but ignore the result because it's not needed for anything
memread_long(&long_value, &addr);
timer.stop();
printf("Getting the FLASH dump took %#.1f seconds.\r\n",timer.read());
fclose(fp);
return TERM_OK;
}
//-----------------------------------------------------------------------------
/**
Erases the flash memory chip starting from [start_addr] up to, but not
including [end_addr] and optionally verifies the result; MCU must be in
background mode.
@param flash_type type of flash chip
@param start_addr flash start address
@param end_addr flash end address
@return status flag
*/
uint8_t erase_flash(const char* flash_type, const uint32_t* start_addr,
const uint32_t* end_addr)
{
// AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7)
if (strncmp(flash_type, "29f010", 6) == 0 ||
strncmp(flash_type, "29f400", 6) == 0) {
return erase_am29() ? TERM_OK : TERM_ERR;
}
// AM28F010 chip (Trionic 5.x original)
if (strncmp(flash_type, "28f010", 6) == 0) {
return erase_am28(start_addr, end_addr) ? TERM_OK : TERM_ERR;
}
return TERM_ERR;
}
//-----------------------------------------------------------------------------
/**
Writes a batch of long words to the flash starting from [start_addr]. The
operation interrupts if a break character is received. MCU must be in
background mode.
@param flash_type type of flash chip
@param start_addr block start address
@return status flag
*/
uint8_t write_flash(const char* flash_type, const uint32_t* start_addr)
{
// set up chip-specific functions
bool (*reset_func)(void);
bool (*flash_func)(const uint32_t*, uint16_t);
// AM29Fxxx chips (retrofitted to Trionic 5.x, original to T7)
if (strncmp(flash_type, "29f010", 6) == 0 ||
strncmp(flash_type, "29f400", 6) == 0) {
reset_func = &reset_am29;
flash_func = &flash_am29;
} else if (strncmp(flash_type, "28f010", 6) == 0) {
// AM28F010 chip (Trionic 5.x original)
reset_func = &reset_am28;
flash_func = &flash_am28;
} else {
// unknown flash type
return TERM_ERR;
}
// reset the flash
if (!reset_func()) {
return TERM_ERR;
}
uint32_t curr_addr = *start_addr;
if (strncmp(flash_type, "29f010", 6) == 0) {
curr_addr = 0;
}
int rx_char = 0;
char rx_buf[8];
char* rx_ptr;
uint32_t long_value;
bool ret = true;
// ready to receive data
pc.putc(TERM_OK);
while (true) {
// receive long words from USB
printf("receive long words from USB\r\n");
rx_ptr = rx_buf;
do {
rx_char = pc.getc();
if (rx_char != EOF) {
// have got all characters for one long word
if (rx_ptr > &rx_buf[7]) {
ret = (rx_char == TERM_OK);
break;
}
// save the character
*rx_ptr++ = (char)rx_char;
}
} while (rx_char != TERM_OK && rx_char != TERM_BREAK);
// end writing
printf("end writing\r\n");
if (!ret || rx_char == TERM_BREAK) {
break;
}
// convert value to long word
printf("convert value to long word\r\n");
if (!ascii2int(&long_value, rx_buf, 8)) {
ret = false;
break;
}
printf("long value %08x \r\n", long_value);
// write the first word
printf("write the first word\r\n");
if (!flash_func(&curr_addr, (uint16_t)(long_value >> 16))) {
ret = false;
break;
}
curr_addr += 2;
// write the second word
printf("write the second word\r\n");
if (!flash_func(&curr_addr, (uint16_t)long_value)) {
ret = false;
break;
}
curr_addr += 2;
// light up the activity LED
ACTIVITYLEDON;
}
// reset flash
return (reset_func() && ret) ? TERM_OK : TERM_ERR;
}
//-----------------------------------------------------------------------------
/**
Writes a BIN file to the flash starting from [start_addr].
The operation ends when no more bytes can be read from the BIN file.
MCU must be in background mode.
@param flash_type type of flash chip
@param start_addr block start address
@return status flag
*/
uint8_t flash_trionic()
{
// Configure the MC68332 register values to prepare for flashing
printf("I am trying to discover what type of Trionic ECU I am connected to...\r\n");
prep_t5_do();
// Work out what type of FLASH chips we want to program
uint8_t make;
uint8_t type;
get_flash_id(&make, &type);
// set up chip-specific functions
bool (*reset_func)();
bool (*flash_func)(const uint32_t*, uint16_t);
uint32_t flash_size;
switch (type) {
case AMD29BL802C:
printf("I have found AMD29BL802C type FLASH chips; I must be connected to a T8 ECU :-)\r\n");
reset_func = &reset_am29;
flash_func = &flash_am29;
flash_size = T8FLASHSIZE;
break;
case AMD29F400B:
case AMD29F400T:
printf("I have found AMD29F400 type FLASH chips; I must be connected to a T7 ECU :-)\r\n");
reset_func = &reset_am29;
flash_func = &flash_am29;
flash_size = T7FLASHSIZE;
break;
case AMD29F010:
printf("I have found AMD29F010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n");
reset_func = &reset_am29;
flash_func = &flash_am29;
flash_size = T55FLASHSIZE;
break;
case AMD28F010:
case INTEL28F010:
printf("I have found 28F010 type FLASH chips; I must be connected to a T5.5 ECU :-)\r\n");
reset_func = &reset_am28;
flash_func = &flash_am28;
flash_size = T55FLASHSIZE;
break;
case AMD28F512:
case INTEL28F512:
printf("I have found 28F512 type FLASH chips; I must be connected to a T5.2 ECU :-)\r\n");
reset_func = &reset_am28;
flash_func = &flash_am28;
flash_size = T52FLASHSIZE;
break;
default:
// unknown flash type
printf("I could not work out what FLASH chips or TRIONIC ECU I am connected to :-(\r\n");
return TERM_ERR;
}
// reset the FLASH chips
printf("Reset the FLASH chip(s) to prepare them for Erasing\r\n");
if (!reset_func()) return TERM_ERR;
printf("Checking the FLASH BIN file...\r\n");
FILE *fp = fopen("/local/modified.hex", "r"); // Open "modified.hex" on the local file system for reading
if (!fp) {
printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");;
return TERM_ERR;
}
// obtain file size - it should match the size of the FLASH chips:
fseek (fp , 0 , SEEK_END);
uint32_t file_size = ftell (fp);
rewind (fp);
// read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU
uint8_t stack_byte = 0;
uint32_t stack_long = 0;
if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
stack_long |= (stack_byte << 24);
if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
stack_long |= (stack_byte << 16);
if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
stack_long |= (stack_byte << 8);
if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
stack_long |= stack_byte;
rewind (fp);
if (flash_size == T52FLASHSIZE && (file_size != T52FLASHSIZE || stack_long != T5POINTER)) {
fclose(fp);
printf("The BIN file does not appear to be for a T5.2 ECU :-(\r\n");
printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long);
return TERM_ERR;
}
if (flash_size == T55FLASHSIZE && (file_size != T55FLASHSIZE || stack_long != T5POINTER)) {
fclose(fp);
printf("The BIN file does not appear to be for a T5.5 ECU :-(\r\n");
printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long);
return TERM_ERR;
}
if (flash_size == T7FLASHSIZE && (file_size != T7FLASHSIZE || stack_long != T7POINTER)) {
fclose(fp);
printf("The BIN file does not appear to be for a T7 ECU :-(\r\n");
printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long);
return TERM_ERR;
}
if (flash_size == T8FLASHSIZE && (file_size != T8FLASHSIZE || stack_long != T8POINTER)) {
fclose(fp);
printf("The BIN file does not appear to be for a T8 ECU :-(\r\n");
printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long);
return TERM_ERR;
}
timer.reset();
timer.start();
uint32_t curr_addr = 0;
switch (type) {
// AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7)
case AMD29BL802C:
case AMD29F400B:
case AMD29F400T:
case AMD29F010:
printf("Erasing 29BL802/F400/010 type FLASH chips...\r\n");
if (!erase_am29()) {
printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n");
return TERM_ERR;
}
break;
// AM28F010 chip (Trionic 5.x original)
case AMD28F010:
case INTEL28F010:
case AMD28F512:
case INTEL28F512:
printf("Erasing 28F010/512 type FLASH chips...\r\n");
if (!erase_am28(&curr_addr, &flash_size)) {
printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n");
return TERM_ERR;
}
break;
default:
// unknown flash type - shouldn't get here hence "Strange!"
printf("Strange! I couldn't work out how to erase the FLASH chips in the TRIONIC ECU that I am connected to :-(\r\n");
return TERM_ERR;
}
timer.stop();
printf("Erasing took %#.1f seconds.\r\n",timer.read());
printf("Programming the FLASH chips...\r\n");
timer.reset();
timer.start();
uint16_t word_value = 0;
uint8_t byte_value = 0;
// bool ret = true;
// ready to receive data
printf(" 0.00 %% complete.\r");
while (curr_addr < flash_size) {
// receive bytes from BIN file
//Get a byte - break if no more bytes to get
if (!fread(&byte_value,1,1,fp)) {
fclose(fp);
printf("Error reading the BIN file MODIFIED.HEX");
break;
}
word_value = (byte_value << 8);
if (!fread(&byte_value,1,1,fp)) {
fclose(fp);
printf("Error reading the BIN file MODIFIED.HEX");
break;
}
word_value |= byte_value;
// write the word if it is not 0xffff
if (word_value != 0xffff) {
if (!flash_func(&curr_addr, word_value)) break;
}
curr_addr += 2;
// make the activity LED twinkle
ACTIVITYLEDON;
if (!(curr_addr % 0x80))
printf("%6.2f\r", 100*(float)curr_addr/(float)flash_size );
}
printf("\n");
timer.stop();
fclose(fp);
if (curr_addr == flash_size) {
printf("Programming took %#.1f seconds.\r\n",timer.read());
// "Just4pleisure;)" 'tag' in the empty space at the end of the FLASH chip
// Removed for now because it conflicts with some information that Dilemma places in this empty space
// and because it is unsafe for Trionic 8 ECUs which have much bigger BIN files and FLASH chips
// reset_func();
// for (uint8_t i = 0; i < 8; ++i) {
// memread_word(&word_value, &flash_tag[i].addr);
// flash_func(&flash_tag[i].addr, (flash_tag[i].val & word_value));
// }
} else
printf("WARNING: Oh dear, I couldn't program the FLASH at address 0x%8x.\r\n", curr_addr);
// reset flash
return (reset_func() && (curr_addr == flash_size)) ? TERM_OK : TERM_ERR;
}
//-----------------------------------------------------------------------------
/**
Resets an AM29Fxxx flash memory chip. MCU must be in background mode.
@param none
@return succ / fail
*/
bool reset_am29(void)
{
// execute the reset command
// uint32_t addr = 0xfffe;
// return (memwrite_word(&addr, 0xf0f0) == TERM_OK);
// execute the algorithm
for (uint8_t i = 0; i < 3; ++i) {
if (memwrite_word(&am29_reset[i].addr, am29_reset[i].val) != TERM_OK) return false;
}
return true;
}
//-----------------------------------------------------------------------------
/**
Erases an AM29Fxxx flash memory chip and verifies the result; MCU must be
in background mode.
@return succ / fail
*/
bool erase_am29()
{
// reset flash
if (!reset_am29()) {
return false;
}
printf("Erasing AMD 29Fxxx FLASH chips.\r\n");
printf("This can take up to a minute for a T8,\r\n");
printf("30s for a T7 or 15s for a T5 ECU.\r\n");
// execute the algorithm
for (uint8_t i = 0; i < 6; ++i) {
if (memwrite_word(&am29_erase[i].addr, am29_erase[i].val) != TERM_OK) {
reset_am29();
return false;
}
}
// verify the result
uint32_t addr = 0x0;
uint16_t verify_value;
printf(" 0.0 seconds.\r");
uint8_t err_cnt = ERR_COUNT;
while (--err_cnt) {
// typical erase time = 1s
// Allow up to 25.5 seconds erase time
wait_ms(100);
wait_ms(100);
if (memread_word(&verify_value, &addr) == TERM_OK && verify_value == 0xffff) {
// erase completed normally
reset_am29();
printf("\n");
return true;
}
// make the activity LED twinkle
ACTIVITYLEDON;
printf("%4.1f\r", (float)ERR_COUNT/5 - (float)err_cnt/5 );
}
printf("\n");
// erase failed
reset_am29();
return false;
}
//-----------------------------------------------------------------------------
/**
Writes a word to AM29Fxxx flash memory chip and optionally verifies the
result; MCU must be in background mode.
@param addr destination address
@param val value
@return succ / fail
*/
bool flash_am29(const uint32_t* addr, uint16_t value)
{
// execute the algorithm
for (uint8_t i = 0; i < 3; ++i) {
if (memwrite_word(&am29_write[i].addr, am29_write[i].val) != TERM_OK) {
reset_am29();
return false;
}
}
// write the value
if (memwrite_word(addr, value) != TERM_OK) {
reset_am29();
return false;
}
// verify the result
uint8_t err_cnt = ERR_COUNT;
while (--err_cnt) {
// Allow up to approx 2.55 milliseconds program time (255 * ~10us BDM memread time)
// wait_ms(10);
wait_us(100);
uint16_t verify_value;
if ((memread_word(&verify_value, addr) == TERM_OK) &&
(verify_value == value)) {
// flashing successful
return true;
}
}
// writing failed
reset_am29();
return false;
}
//-----------------------------------------------------------------------------
/**
Resets a AM28Fxxx flash memory chip. MCU must be in background mode.
@param start_addr flash start address
@return succ / fail
*/
bool reset_am28(void)
{
uint32_t start_addr = 0x0;
return (memwrite_word_write_word(&start_addr, 0xffff, 0xffff) == TERM_OK);
}
//-----------------------------------------------------------------------------
/**
Erases an AM28Fxxx flash memory chip and verifies the result; MCU must be
in background mode.
@param start_addr flash start address
@param end_addr flash end address
@return succ / fail
*/
bool erase_am28(const uint32_t* start_addr, const uint32_t* end_addr)
{
// check the addresses
if (!start_addr || !end_addr) return false;
// reset flash
if (!reset_am28()) return false;
// write zeroes over entire flash space
uint32_t addr = *start_addr;
printf("First write 0x00 to all FLASH addresses.\r\n");
printf(" 0.00 %% complete.\r");
while (addr < *end_addr) {
if (!flash_am28(&addr, 0x0000)) return false;
addr += 2;
// // feedback to host computer
// pc.putc(TERM_OK);
// make the activity LED twinkle
ACTIVITYLEDON;
if (!(addr % 0x80))
printf("%6.2f\r", 100*(float)addr/(float)*end_addr );
}
printf("\n");
// erase flash
addr = *start_addr;
uint8_t verify_value;
printf("Now erasing FLASH and verfiying that all addresses are 0xFF.\r\n");
printf(" 0.00 %% complete.\r");
uint16_t pulse_cnt = 0;
if (memwrite_byte_cmd(NULL) != TERM_OK) {
reset_am28();
return false;
}
while ((++pulse_cnt < 1000) && (addr < *end_addr)) {
// issue the erase command
if (memwrite_write_byte(&addr, 0x20) != TERM_OK ||
memwrite_write_byte(&addr, 0x20) != TERM_OK) break;
wait_ms(10);
while (addr < *end_addr) {
// issue the verify command
if (memwrite_read_byte(&addr, 0xa0) != TERM_OK) break;
// wait_us(6);
// check the written value
if (memread_write_byte(&verify_value, &addr) != TERM_OK) break;
if (verify_value != 0xff) break;
// succeeded need to check next address
addr++;
// make the activity LED twinkle
ACTIVITYLEDON;
if (!(addr % 0x80))
printf("%6.2f\r", 100*(float)addr/(float)*end_addr );
}
}
printf("\n");
// the erase process ends with a BDM_WRITE + BDM_BYTESIZE command left in the BDM
// it is safe to use it to put one of the FLASH chips into read mode and thereby
// leave the BDM ready for the next command
memwrite_nop_byte(start_addr, 0x00);
reset_am28();
// check for success
return (addr == *end_addr) ? true : false;
}
//-----------------------------------------------------------------------------
/**
Writes a byte to AM28Fxxx flash memory chip and verifies the result
A so called 'mask' method checks the FLASH contents and only tries
to program bytes that need to be programmed.
MCU must be in background mode.
@param addr destination address
@param val value
@return succ / fail
*/
bool flash_am28(const uint32_t* addr, uint16_t value)
{
if (!addr) return false;
uint8_t pulse_cnt = 0;
uint16_t verify_value = 0;
uint16_t mask_value = 0xffff;
// put flash into read mode and read address
if (memwrite_word_read_word(&verify_value, addr, 0x0000) != TERM_OK) return false;
// return if FLASH already has the correct value - e.g. not all of the FLASH is used and is 0xff
if (verify_value == value) return true;
while (++pulse_cnt < 25) {
// set a mask
if ((uint8_t)verify_value == (uint8_t)value)
mask_value &= 0xff00;
if ((uint8_t)(verify_value >> 8) == (uint8_t)(value >> 8))
mask_value &= 0x00ff;
// write the new value
if (memwrite_word_write_word(addr, (0x4040 & mask_value), value) != TERM_OK) break;
// NOTE the BDM interface is slow enough that there is no need for a 10us delay before verifying
// issue the verification command
// NOTE the BDM interface is slow enough that there is no need for a 6us delay before reading back
if (memwrite_word_read_word(&verify_value, addr, (0xc0c0 & mask_value)) != TERM_OK) break;
// check if flashing was successful;
if (verify_value == value) return true;
}
// something went wrong; reset the flash chip and return failed
reset_am28();
return false;
}
//-----------------------------------------------------------------------------
/**
Does the equivalent of do prept5.do in BD32
Sets up all of the control registers in the MC68332 so that we can program
the FLASH chips
@param none
@return succ / fail
*/
//uint8_t prep_t5_do(void) {
uint8_t prep_t8_do(void)
{
// reset and freeze the MC68332 chip
if (restart_chip() != TERM_OK) return TERM_ERR;
// set the 'fc' registers to allow supervisor mode access
uint32_t long_value = 0x05;
if (sysreg_write(0x0e, &long_value) != TERM_OK) return TERM_ERR;
if (sysreg_write(0x0f, &long_value) != TERM_OK) return TERM_ERR;
// Set MC68332 to 16 MHz (actually 16.78 MHz) (SYNCR)
long_value = 0x00fffa04;
if (memwrite_word(&long_value, 0x7f00) != TERM_OK) return TERM_ERR;
// Disable watchdog and monitors (SYPCR)
long_value = 0x00fffa21;
if (memwrite_byte(&long_value, 0x00) != TERM_OK) return TERM_ERR;
// Chip select pin assignments (CSPAR0)
long_value = 0x00fffa44;
if (memwrite_word(&long_value, 0x3fff) != TERM_OK) return TERM_ERR;
// Boot Chip select read only, one wait state (CSBARBT)
long_value = 0x00fffa48;
if (memwrite_word(&long_value, 0x0007) != TERM_OK) return TERM_ERR;
if (memfill_word(0x6870) != TERM_OK) return TERM_ERR;
// Chip select 1 and 2 upper lower bytes, zero wait states (CSBAR1, CSOR1, CSBAR2, CSBAR2)
long_value = 0x00fffa50;
if (memwrite_word(&long_value, 0x0007) != TERM_OK) return TERM_ERR;
if (memfill_word(0x3030) != TERM_OK) return TERM_ERR;
if (memfill_word(0x0007) != TERM_OK) return TERM_ERR;
if (memfill_word(0x5030) != TERM_OK) return TERM_ERR;
// PQS Data - turn on VPPH (PORTQS)
long_value = 0x00fffc14;
if (memwrite_word(&long_value, 0x0040) != TERM_OK) return TERM_ERR;
// PQS Data Direction output (DDRQS)
long_value = 0x00fffc17;
if (memwrite_byte(&long_value, 0x40) != TERM_OK) return TERM_ERR;
// wait for programming voltage to be ready
wait_ms(10);
// // Enable internal 2kByte RAM of 68332 at address 0x00100000 (TRAMBAR)
// long_value = 0x00fffb04;
// if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR;
return TERM_OK;
}
//-----------------------------------------------------------------------------
/**
Does the equivalent of do prept5/7/8.do in BD32
Sets up all of the control registers in the MC68332/377 so that we can
program the FLASH chips
@param none
@return succ / fail
*/
uint8_t prep_t5_do(void)
{
// reset and freeze the MC68332/377 chip
if (restart_chip() != TERM_OK) return TERM_ERR;
// define some variables to store address and data values
uint32_t long_value = 0x05;
uint16_t verify_value;
// set the 'fc' registers to allow supervisor mode access
if (sysreg_write(0x0e, &long_value) != TERM_OK) return TERM_ERR;
if (sysreg_write(0x0f, &long_value) != TERM_OK) return TERM_ERR;
// Read MC68332/377 Module Control Register (SIMCR/MCR)
// and use the value to work out if ECU is a T5/7 or a T8
long_value = 0x00fffa00;
if (memread_word(&verify_value, &long_value) != TERM_OK) return TERM_ERR;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// verify_value = 0x7E4F;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MC68377 MCR = x111111x01001111 binary after a reset
if ((verify_value & 0x7E4F) == 0x7E4F) {
printf ("I have found a Trionic 8 ECU.\r\n");
// Set MC68377 to double it's default speed (16 MHz?) (SYNCR)
long_value = 0x00fffa08;
// First set the MFD part (change 4x to 8x)
if (memwrite_word(&long_value, 0x6908) != TERM_OK) return TERM_ERR;
// wait for everything to settle (should really check the PLL lock register)
wait_ms(100);
// Now set the RFD part (change /2 to /1)
if (memwrite_word(&long_value, 0x6808) != TERM_OK) return TERM_ERR;
// Disable watchdog and monitors (SYPCR)
long_value = 0x00fffa50;
if (memwrite_word(&long_value, 0x0000) != TERM_OK) return TERM_ERR;
return TERM_OK;
}
// MC68332 SIMCR = 0000x00011001111 binary after a reset
//if ((verify_value & 0x00CF) == 0x00CF) {
else {
printf ("I have found a Trionic 5 or 7 ECU.\r\n");
// Set MC68332 to 16 MHz (actually 16.78 MHz) (SYNCR)
long_value = 0x00fffa04;
if (memwrite_word(&long_value, 0x7f00) != TERM_OK) return TERM_ERR;
// Disable watchdog and monitors (SYPCR)
long_value = 0x00fffa21;
if (memwrite_byte(&long_value, 0x00) != TERM_OK) return TERM_ERR;
// Chip select pin assignments (CSPAR0)
long_value = 0x00fffa44;
if (memwrite_word(&long_value, 0x3fff) != TERM_OK) return TERM_ERR;
// Boot Chip select read only, one wait state (CSBARBT)
long_value = 0x00fffa48;
if (memwrite_word(&long_value, 0x0007) != TERM_OK) return TERM_ERR;
if (memfill_word(0x6870) != TERM_OK) return TERM_ERR;
// Chip select 1 and 2 upper lower bytes, zero wait states (CSBAR1, CSOR1, CSBAR2, CSBAR2)
long_value = 0x00fffa50;
if (memwrite_word(&long_value, 0x0007) != TERM_OK) return TERM_ERR;
if (memfill_word(0x3030) != TERM_OK) return TERM_ERR;
if (memfill_word(0x0007) != TERM_OK) return TERM_ERR;
if (memfill_word(0x5030) != TERM_OK) return TERM_ERR;
// PQS Data - turn on VPPH (PORTQS)
long_value = 0x00fffc14;
if (memwrite_word(&long_value, 0x0040) != TERM_OK) return TERM_ERR;
// PQS Data Direction output (DDRQS)
long_value = 0x00fffc17;
if (memwrite_byte(&long_value, 0x40) != TERM_OK) return TERM_ERR;
// wait for programming voltage to be ready
wait_ms(10);
// Enable internal 2kByte RAM of 68332 at address 0x00100000 (TRAMBAR)
//long_value = 0x00fffb04;
//if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR;
return TERM_OK;
}
// Unknown MC683xx chip if code reaches this point
return TERM_ERR;
}
//-----------------------------------------------------------------------------
/**
Works out what type of flash chip is fitted in the ECU by reading
the manufacturer byte codes.
It is enough to use the 29Fxxx flash id algorithm because 28Fxxx
FLASH chips ignore the first few writes needed by the 29Fxxx chips
MCU must be in background mode.
@param make (out)
type (out)
@return succ / fail
*/
bool get_flash_id(uint8_t* make, uint8_t* type)
{
uint32_t addr = 0x0;
uint32_t value;
bool ret;
// read id bytes algorithm for 29F010/400 FLASH chips
for (uint8_t i = 0; i < 3; ++i) {
//printf("Getting FLASH chip ID.\r\n");
if (memwrite_word(&am29_id[i].addr, am29_id[i].val) != TERM_OK) {
printf("There was an error when I tried to request the FLASH chip ID.\r\n");
return false;
}
}
if (memread_long(&value, &addr) != TERM_OK) {
printf("Error Reading FLASH chip types in get_flash_id\r\n");
return false;
}
// *make = (uint8_t)(value >> 24);
// *type = (uint8_t)(value >> 8);
*make = (uint8_t)(value >> 16);
*type = (uint8_t)(value);
printf("FLASH id bytes: %08x, make: %02x, type: %02x\r\n", value, *make, *type);
switch (*type) {
case AMD29BL802C:
case AMD29F400B:
case AMD29F400T:
case AMD29F010:
case AMD28F010:
case INTEL28F010:
case AMD28F512:
case INTEL28F512:
ret = true;
default:
ret = false;
}
return ret;
}
//-----------------------------------------------------------------------------
// EOF
//-----------------------------------------------------------------------------