Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
Revision 1:d5452e398b76, committed 2010-09-14
- Comitter:
- Just4pLeisure
- Date:
- Tue Sep 14 21:02:04 2010 +0000
- Parent:
- 0:e0b964252a05
- Child:
- 2:bf3a2b29259a
- Commit message:
Changed in this revision
--- a/BDM.cpp Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ - -#include "BDM.h" - -void BDM() { -} \ No newline at end of file
--- a/BDM.h Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -// BDM.h - -extern void BDM(); \ No newline at end of file
--- a/CAN232.cpp Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ - -#include "CAN232.h" - -void CAN232() { -} \ No newline at end of file
--- a/CAN232.h Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -// CAN232.h - -extern void CAN232(); \ No newline at end of file
--- a/CANUtils.cpp Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -// CANUtils.cpp - functions that work with the CAN bus directly -// Anything to do with the CAN bus must (should anyway) be done by one of these functions. - -#include "CANUtils.h" - -// CAN_RS pin at Philips PCA82C250 can bus controller. -// activate transceiver by pulling this pin to GND. -// (Rise and fall slope controlled by resistor R_s) -// (+5V result in tranceiver standby mode) -// For further information see datasheet page 4 -DigitalOut can_Pca82c250SlopePin(p28);// second can controller on these pins. Not used here. -// CAN can1(p9, p10); -// We use can on mbed pins 29(CAN_TXD) and 30(CAN_RXD). -CAN can2(p30, p29); -// Use a timer to see if things take too long -Timer CANTimer; - -// Use the LEDs to if anything is happening on the CAN bus -// LED1 CAN send -DigitalOut led1(LED1); -// LED2 CAN receive -DigitalOut led2(LED2); - - -void CANOpen() { - // 600kbit/s first - basically sets up CAN interface, but to wrong speed - not sure what else it does - can2.frequency(600000); - // 615kbit/s direct write of 615 kbit/s speed setting - LPC_CAN2->BTR = 0x370002; - // activate external can transceiver - can_Pca82c250SlopePin = 0; -} - -void CANClose() { - // disable external can transceiver - can_Pca82c250SlopePin = 1; -} - -// -// Sends a CAN Message, returns FALSE if the message wasn't sent in time -// -// inputs: integer CAN message 'id', pointer to 'frame', integer message length and integer timeout -// return: TRUE if the CAN message was sent before the 'timeout' expires -// FALSE if 'timeout' expires or the message length is wrong -// -extern bool CANSendTimeout (int id, char *frame, int len, int timeout) { - CANTimer.reset(); - CANTimer.start(); - while (CANTimer.read_ms() < timeout) { - if (can2.write(CANMessage(id, frame, len))) { - CANTimer.stop(); - led1 = !led1; - return TRUE; - } - } - CANTimer.stop(); - return FALSE; -} - -// -// Waits for a CAN Message with the specified 'id' for a time specified by the 'timeout' -// All other messages are ignored -// The CAN message frame is returned using the pointer to 'frame' -// -// inputs: integer CAN message 'id', pointer to 'frame' for returning the data -// integer expected length of message, len and integer for the waiting time 'timeout' -// -// return: TRUE if a qualifying message was received -// FALSE if 'timeout' expires or the message length is wrong -// -extern bool CANWaitTimeout (int id, char *frame, int len, int timeout) { - CANMessage CANMsgRx; - CANTimer.reset(); - CANTimer.start(); - while (CANTimer.read_ms() < timeout) { - if (can2.read(CANMsgRx)) { -/* - printf("w%03x8", CANMsgRx.id); - for (char i=0; i<len; i++) { - printf("%02x", CANMsgRx.data[i]); - } - printf("\n\r"); -// */ - led2 = !led2; - if (CANMsgRx.id == id) { - CANTimer.stop(); -// if (T5MsgRx.len != len) -// return FALSE; - for (int i=0; i<len; i++) - frame[i] = CANMsgRx.data[i]; - return TRUE; - } - } - } - CANTimer.stop(); - return FALSE; -}
--- a/CANUtils.h Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ - -// CANUtils.h - information and definitions needed for the CAN bus - -#include "CAN.h" -#include "mbed.h" - -#define TRUE 1 -#define FALSE 0 - -extern void CANOpen(); -extern void CANClose(); - -extern bool CANSendTimeout (int id, char *frame, int len, int timeout); -extern bool CANWaitTimeout (int id, char *frame, int len, int timeout);
--- a/SRecUtils.cpp Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ - -#include "SRecUtils.h" - -// SRecGetByte -// -// Returns an int which is a single byte made up from two ascii characters read from an S-record file -// -// inputs: a file pointer for the S-record file -// return: an integer which is the byte in hex format - -int SRecGetByte(FILE *fp) { - int c = 0; - int retbyte = 0; - - for(int i=0; i<2; i++) { - if ((c = fgetc(fp)) == EOF) return -1; - c -= (c > '9') ? ('A' - 10) : '0'; - retbyte = (retbyte << 4) + c; - } - return retbyte; -} - -// SRecGetAddress -// -// Returns an int which is the address part of the S-record line -// The S-record type 1/2/3 or 9/8/7 determines if there are 2, 3 or 4 bytes in the address -// -// inputs: an integer which is the number of bytes that make up the address; 2, 3 or 4 bytes -// a file pointer for the S-record file -// return: an integer which is the load address for the S-record - -int SRecGetAddress(int size, FILE *fp) { - int address = 0; - for (int i = 0; i<size; i++) - { - address <<= 8; - address |= SRecGetByte (fp); - } - return address; -} \ No newline at end of file
--- a/SRecUtils.h Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ - -// SRecUtils.h - information and definitions needed for working with S-Records - -#include "mbed.h" - -#define TRUE 1 -#define FALSE 0 - -extern int SRecGetByte(FILE *fp); -extern int SRecGetAddress(int size, FILE *fp);
--- a/T5Utils.cpp Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,389 +0,0 @@ -/******************************************************************************* - -T5Utils.cpp - By Sophie Dexter, April 2010 - -This C++ module provides functions for communicating simple messages to and from -the T5 ECU - -******************************************************************************** - -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 "T5Utils.h" - -// -// T5Open enables the CAN chip and sets the CAN speed to 615 kbits. -// -// This function is a 'quick fix' for now. -// -// inputs: none -// return: bool TRUE if all went OK, -// -bool T5Open() { - CANOpen (); - return TRUE; -} - -// -// T5Close disables the CAN chip. -// -// This function is a 'quick fix' for now. -// -// inputs: none -// return: bool TRUE if all went OK, -// -bool T5Close() { - CANClose (); - return TRUE; -} - -// -// T5WaitResponse -// -// Waits for a response message with the correct message id from the T5 ECU. -// The response is a single ascii character from the symboltable. -// -// Returns an error ('BELL' character) if: -// a response is not received before the timeout -// the message length is less than 8 bytes (all messages should be 8 bytes) -// the message type is incorrect -// -// inputs: none -// return: a single char that is the response from the T5 ECU -// -char T5WaitResponse() { - char T5RxMsg[8]; - if (!CANWaitTimeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return '\a'; - if (T5RxMsg[0] != 0xC6) return '\a'; - return T5RxMsg[2]; -} - -// -// -// T5WaitResponsePrint -// -// Waits for a response message with the correct message id from the T5 ECU and displays the whole message: -// -// wiiildddddddddddddddd -// iii - is the CAN message id -// l - is the message length, should always be 8 for T5 messages -// dd,dd,dd,dd,dd,dd,dd,dd are the CAN message data bytes -// -// Returns an error if: -// a response is not received before the timeout -// the message length is less than 8 bytes (all messages should be 8 bytes) -// the message type is incorrect -// -// Inputs: none -// return: bool TRUE if a qualifying message was received -// FALSE if a message wasn't received in time, had the wrong id etc... -// -bool T5WaitResponsePrint() { - char T5RxMsg[8]; - if (!CANWaitTimeout(RESPID, T5RxMsg, 8, T5CHECKSUMTIMEOUT)) return FALSE; - printf("w%03x8", RESPID); - for (char i=0; i<8; i++) { - printf("%02x", T5RxMsg[i]); - } - printf("\n\r"); - return TRUE; -} - -// T5GetSymbol -// -// Reads a single symbol name (in the symbol table) from the T5 ECU. -// T5GetSymbol sends ACK messages to the T5 ECU and stores the -// reply characters in a string until a '\n' character is received -// when the function returns with the pointer to that string. -// -// inputs: a pointer to the string used to store the symbol name. -// return: a pointer to the string used to store the symbol name. -// -char *T5GetSymbol(char *s) { - do { - if (T5Ack()) { - } - *s = T5WaitResponse(); - } while (*s++ != '\n'); - *s = '\0'; - return s; -} - -// T5ReadCmnd -// -// Sends a 'read' type command to the T5 ECU. 'read' commands are used to read something from the T5 ECU. -// -// inputs: a 'char' which is the type of 'read' requested (e.g. symbol table, version etc). -// return: bool TRUE if the message was sent within the timeout period, -// FALSE if the message couldn't be sent. -// -bool T5ReadCmnd(char c) { - char T5TxMsg[] = T5_RDCMND; - T5TxMsg[1] = c; - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5WriteCmnd is unfinished -// -bool T5WriteCmnd(unsigned int addr, char data) { - return FALSE; -} - -// T5ReadRAM -// -// Reads 6 bytes of the adaption data from the SRAM in the T5 ECU. -// -// inputs: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. -// the address to read SRAM data from in the T5 ECU -// return: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. -// -char *T5ReadRAM(char *data, unsigned int addr) { - T5RAMCmnd(addr); - T5WaitRAM(data); - return data; -} - -// T5ReadFLASH -// -// Reads 6 bytes of the FLASH in the T5 ECU. -// -// inputs: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. -// the address to read SRAM data from in the T5 ECU -// return: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. -// -char *T5ReadFLASH(char *data, unsigned int addr) { - T5RAMCmnd(addr); - T5WaitRAM(data); - return data; -} - -// -// T5RAMCmnd -// -// Sends a command to the ECU asking the T5 ECU to send some SRAM data -// -// inputs: the address to read SRAM data from in the T5 ECU -// return: bool TRUE if the message was sent within the timeout period, -// FALSE if the message couldn't be sent. -// -bool T5RAMCmnd(unsigned int addr) { - char T5TxMsg[] = T5RAMCMND; - T5TxMsg[1] = ((char)(addr >> 24)); // high high byte of address - T5TxMsg[2] = ((char)(addr >> 16)); // high low byte of address - T5TxMsg[3] = ((char)(addr >> 8)); // low high byte of address - T5TxMsg[4] = ((char)(addr)); // low low byte of address - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5WaitRAM -// -// Waits for the T5 ECU to send some SRAM data -// -// There is something back-to-front about the way this works, but it does :-) -// -// inputs: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. -// return: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. -// -char *T5WaitRAM(char *data) { - char T5RxMsg[8]; - CANWaitTimeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT); -// if (T5RxMsg[0] != 0xC6) return FALSE; -// if (T5RxMsg[0] != 0x0C) return FALSE; - for (int i=2; i<8; i++) - data[7-i] = T5RxMsg[i]; - return data; -} - -// T5Ack -// -// Sends an 'ACK' message to the T5 ECU to prompt the T5 to send the next -// ascii character from the symboltable -// -// Returns an error if: -// the 'ACK' message cannot be sent before the timeout -// -// inputs: none -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. - -bool T5Ack() { - char T5TxMsg[] = T5ACKCMND; - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5SendBootAddress -// -// Send an address where 'bootloader' or FLASH CAN messages are uploaded to. -// The number of bytes (up to 0x7F) that will be sent in the following CAN messages is also sent. -// -// inputs: an unsigned int, the address where messages should be sent. -// an int, the number of bytes (up to 0x7F) that will be sent in the following CAN messages. -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -bool T5SendBootAddress(unsigned int addr, int len) { - char T5TxMsg[] = T5_BTCMND; - T5TxMsg[1] = ((char)(addr >> 24)); // high high byte of address - T5TxMsg[2] = ((char)(addr >> 16)); // high low byte of address - T5TxMsg[3] = ((char)(addr >> 8)); // low high byte of address - T5TxMsg[4] = ((char)(addr)); // low low byte of address - T5TxMsg[5] = ((char)(len)); // number of bytes to upload (sent in following messages) - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// Upload 'bootloader' or new FLASH byts to T5 ECU in CAN messages -// -// The CAN messages are made up of 1 byte which is added to the address given in the T5SendBootAddress meaassge -// followed by 7 bytes of data. -// The first byte normally starts at 0x00 and increases by 7 in following messages until another T5SendBootAddress message is sent e.g. -// 00,dd,dd,dd,dd,dd,dd,dd,dd 'dd' bytes are the data bytes, 7 in each CAN message except the last one which may have less. -// 07,dd,dd,dd,dd,dd,dd,dd,dd -// 0E,dd,dd,dd,dd,dd,dd,dd,dd (0x0E is 14) -// 15,dd,dd,dd,dd,dd,dd,dd,dd (0x15 is 21) -// etc. -// -// inputs: a pointer to an array of 8 bytes to be sent to the T5 ECU SRAM or FLASH. -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -bool T5SendBootFrame (char *frame) { - return (CANSendTimeout (CMNDID, frame, 8, T5MESSAGETIMEOUT)); -} - -// -// T5StartBootLoader -// -// Send the jump to address to the T5 ECU for starting the 'bootloader'. -// The jump address must be somewhere in RAM (addresses 0x0000 to 0x8000). -// (The start address comes from the S7/8/9 line in the S19 file.) -// -// inputs: an unsigned int, the address to jump to start of 'bootloader'. -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -bool T5StartBootLoader (unsigned int addr) { - char T5TxMsg[] = T5JMPCMND; - T5TxMsg[3] = ((char)(addr >> 8)); // low byte of address - T5TxMsg[4] = ((char)(addr)); // high byte of address - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5BootCSumCmnd -// -// Send the checksum command to Bootloader -// -// inputs: none -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -bool T5BootCSumCmnd() { - char T5TxMsg[] = T5SUMCMND; - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5BootResetCmnd -// -// Send 'exit and restart T5' command to the Bootloader -// -// inputs: none -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -bool T5BootResetCmnd() { - char T5TxMsg[] = T5RSTCMND; - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5BootFLASHType -// -// Send 'get FLASH chip types' command to the Bootloader -// -// inputs: none -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -bool T5BootFLASHType() { - char T5TxMsg[] = T5TYPCMND; - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5BootEraseCmnd -// -// Send 'erase FLASH chip types' command to the Bootloader -// -// inputs: none -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -bool T5BootEraseCmnd() { - char T5TxMsg[] = T5ERACMND; - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5BootDumpFLASHCmnd -// -// Send 'Dump FLASH BIN file' command -// -// inputs: none -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -extern bool T5BootDumpFLASHCmnd() { - char T5TxMsg[] = T5DMPCMND; - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} - -// -// T5WaitFLASH -// -// Waits for the T5 ECU to send 4 bytes of FLASH data when dumping the FLASH -// -// CAN messages look like this: -// A6,04,dd,dd,dd,dd,08,08 -// A6 - means FLASH dump type message -// 04 - means (at least) 4 more bytes still to come -// dd,dd,dd,dd are 4 data bytes -// The last message looks like this: -// A6,00,dd,dd,dd,dd,08,08 -// A6 - means FLASH dump type message -// 00 - means no more bytes after this CAN message -// dd,dd,dd,dd are the last 4 data bytes -// -// inputs: a pointer to an array of 8 bytes for the CAN message containing FLASH data. -// return: a pointer to an array of 8 bytes for the CAN message containing FLASH data. -// -char *T5WaitFLASH(char *data) { - char T5RxMsg[8]; - CANWaitTimeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT); -// if (T5RxMsg[0] != 0xC6) return FALSE; -// if (T5RxMsg[0] != 0x0C) return FALSE; - for (int i=0; i<8; i++) - data[i] = T5RxMsg[i]; - return data; -} - -// -// T5BootResetCmnd -// -// Send 'C3 - Get last address' command to the Bootloader -// -// inputs: none -// return: bool TRUE if message was sent OK, -// FALSE if message could not be sent. -// -bool T5BootC3Command() { - char T5TxMsg[] = T5EOFCMND; - return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); -} \ No newline at end of file
--- a/T5Utils.h Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ - -// T5Utils.h - information and definitions needed for communicating with the T5 ECU - -#include "mbed.h" -#include "CANUtils.h" - -#define TRUE 1 -#define FALSE 0 - -#define CMNDID 0x05 -#define ACK_ID 0x06 -#define RESPID 0x0C - -#define T5_RDCMND {0xC4,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} // C4 Command template for reading something from the T5 ECU -#define T5_WRCMND {0xC4,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C4 Command template for writing something to the T5 ECU -#define T5ACKCMND {0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C6 Command for acknowledging receipt of last message from T5 ECU or - // asking it to send some more data (e.g. symbol table) I'm not sure which :lol: -#define T5_BTCMND {0xA5,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // A5 Command template for sending a bootloader to the T5 ECU -#define T5JMPCMND {0xC1,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C1 Command template for starting a bootloader that has been sent to the T5 ECU -#define T5EOFCMND {0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C3 Command for reading back the last address of FLASH in the T5 ECU -#define T5A_DCMND {0xC5,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C5 Command for setting analogue to digital registers (don't know what this is for) -//#define T5RAMCMND {0xC7,0x00,0x00,0x00,0x00,0xFC,0xC4,0x77} // C7 Command for reading T5 RAM (all the symbols and adaption data is in RAM) -#define T5RAMCMND {0xC7,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C7 Command for reading T5 RAM (all the symbols and adaption data is in RAM) - - -#define T5DMPCMND {0xA6,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // A6 Command for dumping the T5 FLASH BIN file (Bootloader must be loaded before using) -#define T5ERACMND {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C0 Command for erasing T5 FLASH Chips !!! (Bootloader must be loaded before using) -#define T5RSTCMND {0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C2 Command for exiting the Bootloader and restarting the T5 ECU (Bootloader must be loaded before using) -#define T5SUMCMND {0xC8,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C8 Command for reading T5 FLASH Checksum (Bootloader must be loaded before using) -#define T5TYPCMND {0xC9,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C9 Command for reading T5 FLASH Chip types (Bootloader must be loaded before using) - - -#define T5MESSAGETIMEOUT 500 // 500 milliseconds (half a second) - Seems to be plenty of time to wait for messages on the CAN bus -#define T5CHECKSUMTIMEOUT 60000 // 60 seconds (60,000 milliseconds) - Usually takes less than 2 seconds so allowing 10 is plenty -// - Increased to 60 seconds for now because using it as erase timeout too - -extern bool T5Open(); -extern bool T5Close(); -extern char T5WaitResponse(); -extern bool T5WaitResponsePrint(); -extern char *T5GetSymbol(char *a_symbol); -extern bool T5ReadCmnd(char c); -extern bool T5WriteCmnd(unsigned int addr, char data); -extern char *T5ReadRAM(char *data, unsigned int addr); -extern char *T5ReadFLASH(char *data, unsigned int addr); -extern bool T5RAMCmnd(unsigned int addr); -extern char *T5WaitRAM(char *data); -extern bool T5Ack(); -extern bool T5SendBootAddress(unsigned int addr, int len); -extern bool T5SendBootFrame (char *frame); -extern bool T5StartBootLoader (unsigned int addr); - -extern bool T5BootCSumCmnd(); -extern bool T5BootResetCmnd(); -extern bool T5BootFLASHType(); -extern bool T5BootEraseCmnd(); -extern bool T5BootDumpFLASHCmnd(); -extern char *T5WaitFLASH(char *data); -extern bool T5BootC3Command(); \ No newline at end of file
--- a/Trionic5.cpp Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,728 +0,0 @@ -/******************************************************************************* - -Trionic5.cpp - By Sophie Dexter, April 2010 - -This C++ module provides functions for reading and writing the FLASH chips and -SRAM in Trionic5 ECUs. (Writing the adaption data back to SRAM not done yet). - -Some functions need an additional 'bootloader' program to be sent to the T5 ECU -before they can be used. These functions are: Identifying the T5 ECU type and -FLASH chips, dumping the FLASH chips, erasing the FLASH chips, writing to the -FLASH chips and calculating the FLASH chips' checksum. - -My version of the bootloader, BOOTY.S19, includes some features not in other -bootloaders; identifying the ECU and FLASH chip types, a 'safer' way of dumping -the FLASH chips and the ability to program AMD 29F010 type FLASH chips (NOTE -that AMD 29F010 FLASH programming is experimental at this stage to say the least) - -******************************************************************************** - -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 "Trionic5.h" - -// RS232 on USB connection -Serial pc2(USBTX, USBRX); // tx, rx - -// A timer for timing how long things take to happen -Timer timer; - -// We use CAN on mbed pins 29(CAN_TXD) and 30(CAN_RXD). -CAN can_temp(p30, p29); - -// Need to create this to be able to read and write files on the mbed 'disk' -LocalFileSystem local("local"); - -void Trionic5() { - // Start the CAN bus system - // Note that at the moment this is only for T5 ECUs at 615 kbits - CANOpen(); - - int counter = 0; //counter used for testing things !?! - - Trionic5ShowHelp(); - - while (1) { - // send received messages to the pc over USB connection - // This function displays any CAN messages that are 'missed' by the other functions - // Can messages might be 'missed' because they are received after a 'timeout' period - // or because they weren't expected, e.g. if the T5 ECU resets for some reason - Trionic5ShowCANMessage(); - -// Wait for a single command character from the PC - if (pc2.readable()) { -// char command[30] = "w0068c600000000000000"; -// command = pc2.gets(); - char c = (pc2.getc()); - if ((c=='h') || (c=='H')) Trionic5ShowHelp(); // Print help - if (c=='\e') return; // 'ESC' key to go back to mbed CAN tool menu -// if ((c=='s') or (c=='S')) { - if (c=='s') Trionic5GetSymbolTable(); // Get the Symbol Table - if (c=='S') T5ReadCmnd(T5SYMBOLS); -// if ((c=='v') or (c=='V')) { - if (c=='v') Trionic5GetVersion(); // Get the Trionic5 software version string - if (c=='V') T5ReadCmnd(T5VERSION); -// if ((c=='r') or (c=='R')) { - if (c=='r') Trionic5GetAdaptionData(); // Read Adaption Data from RAM and write it to a file - if (c=='R') T5RAMCmnd(counter++); - if (c=='\r') T5ReadCmnd(CR); // CR - send CR type message - -// if ((c=='a') or (c=='A')) { - if (c=='a') { // Get a single symbol from the Symbol Table - char symbol[40]; - T5GetSymbol(symbol); - printf("%s",symbol); - } - if (c=='A') T5Ack(); // Just send an 'ACK' message - if ((c=='b') or (c=='B')) Trionic5SendBootLoader(); // Send a Bootloader file to the T5 ECU - if ((c=='c') or (c=='C')) Trionic5GetChecksum(); // Get Checksum from ECU (Bootloader must be uploaded first) - if ((c=='q') or (c=='Q')) Trionic5BootloaderReset(); // Exit the BootLoader and restart the T5 ECU - if ((c=='e') or (c=='E')) Trionic5EraseFLASH(); // Erase the FLASH chips - if ((c=='t') or (c=='T')) Trionic5GetChipTypes(); // Read back the FLASH chip types -// if ((c=='d') or (c=='D')) Trionic5DumpFLASH(); // DUMP the T5 ECU BIN file stored in the FLASH chips -// if (c=='d') Trionic5DumpFLASH(); // DUMP the T5 ECU BIN file stored in the FLASH chips -// if (c=='D') Trionic5DumpFLASH2(); // DUMP the T5 ECU BIN file stored in the FLASH chips - if ((c=='d') or (c=='D')) Trionic5DumpFLASH2(); // DUMP the T5 ECU BIN file stored in the FLASH chips - if ((c=='f') or (c=='F')) Trionic5SendFLASHUpdate(); // Send a FLASH update file to the T5 ECU - if (c=='3') Trionic5SendC3Message(); // Send the C3 message - should get last used address 0x7FFFF - } - } -} - -// -// Trionic5ShowHelp -// -// Displays a list of things that can be done with the T5 ECU. -// -// inputs: none -// return: none -// -void Trionic5ShowHelp() { - printf("Trionic 5 Command Menu\r\n"); - printf("======================\r\n"); - printf("b - upload and start MyBooty.S19 bootloader\r\n"); - printf("c - get T5 ECU FLASH checksum (need toupload BOOTY.S19 before using this command)\r\n"); - printf("d - dump the T5 FLASH BIN file and write it to ORIGINAL.HEX\r\n"); - printf("e - erase the FLASH chips in the T5 ECU\r\n"); - printf("f - FLASH the upate file MODIFIED.S19 to the T5 ECU\r\n"); - printf("e - erase the FLASH chips in the T5 ECU\r\n"); - printf("r - read SRAM and write it to ADAPTION.HEX file\r\n"); - printf("s - read Symbol Table, display it and write it to SYMBOLS.TXT\r\n"); - printf("v - read T5 ECU software version, display it and write it to VERSION.TXT\r\n"); - printf("q - exit the bootloader and reset the T5 ECU\r\n"); - printf("t - read the FLASH chip type in the T5 ECU\r\n"); - printf("3 - read the last used FLASH address in the T5 ECU\r\n"); - printf("S - send 's' message (to get symbol table)\r\n"); - printf("V - send 'S' message (to get software version)\r\n"); - printf("'Enter' Key - send an CR message\r\n"); - printf("a - send an ACK\r\n"); - printf("A - read a single symbol from the symbol table\r\n"); - printf("\r\n"); - printf("'ESC' - return to mbed CAN tool Menu\r\n"); - printf("\r\n"); - printf("h/H - show this help menu\r\n"); - return; -} - -// -// Trionic5ShowCANMessage -// -// Displays a CAN message in the RX buffer if there is one. -// -// inputs: none -// return: bool TRUE if there was a message, FALSE if no message. -// -bool Trionic5ShowCANMessage() { - CANMessage can_MsgRx; - if (can_temp.read(can_MsgRx)) { - printf("w%03x%d", can_MsgRx.id, can_MsgRx.len); - for (char i=0; i<can_MsgRx.len; i++) { - printf("%02x", can_MsgRx.data[i]); - } - printf(" %c ", can_MsgRx.data[2]); - printf("\r\n"); - return TRUE; - } - return FALSE; -} - -// -// Trionic5GetSymbolTable -// -// Gets the T5 ECU symbol table. -// The Symbol Table is sent to the PC and saved to a file, symbols.txt, on the mbed 'local' file system 'disk'. -// -// inputs: none -// return: bool TRUE if there all went OK, FALSE if there was an error -// -bool Trionic5GetSymbolTable() { - FILE *fp = fopen("/local/symbols.txt", "w"); // Open "symbols.txt" on the local file system for writing - if (!fp) return FALSE; - char symbol[40]; - char response = '\0'; - T5ReadCmnd(T5SYMBOLS); - response = T5WaitResponse(); - if (response != '>') - return FALSE; -// printf("%c",response); - T5ReadCmnd(CR); - response = T5WaitResponse(); - if (response != '>') - return FALSE; -// printf("%c",response); - timer.reset(); - timer.start(); - do { - T5GetSymbol(symbol); - printf("%s",symbol); - fprintf(fp,"%s",symbol); - } while (!StrCmp(symbol,"END\r\n")); - timer.stop(); - printf("Getting the Symbol Table took %f seconds.\r\n",timer.read()); - fclose(fp); - return TRUE; -} - -// -// Trionic5GetVersion -// -// Gets the T5 software version string. -// The software version is is sent to the PC and saved to a file, version.txt, on the mbed 'local' file system 'disk'. -// -// inputs: none -// return: bool TRUE if there all went OK, FALSE if there was an error -// -bool Trionic5GetVersion() { - FILE *fp = fopen("/local/version.txt", "w"); // Open "version.txt" on the local file system for writing - if (!fp) return FALSE; - char symbol[40]; - char response = '\0'; - T5ReadCmnd(T5VERSION); - response = T5WaitResponse(); - if (response != '>') - return FALSE; -// printf("%c",response); - T5ReadCmnd(CR); - response = T5WaitResponse(); - if (response != '>') - return FALSE; -// printf("%c",response); - T5GetSymbol(symbol); - printf("%s",symbol); - if (fp) - fprintf(fp,"%s",symbol); - else - printf("ERROR Could not open version.txt for saving\r\n"); - fclose(fp); - return TRUE; -} - -// -// Trionic5GetAdaptionData -// -// Gets the adaption data from the T5's SRAM. -// The adaption data is stored in a hex file, adaption.hex, on the mbed 'local' file system 'disk'. -// -// Reading the Adaption data from SRAM takes about 16 seconds. -// -// inputs: none -// return: bool TRUE if all went OK, FALSE if there was an error. -// -bool Trionic5GetAdaptionData() { - printf("getting adaption data\r\n"); - FILE *fp = fopen("/local/adaption.hex", "w"); // Open "adaption.hex" on the local file system for writing - if (!fp) return FALSE; - printf("opened adaption data file\r\n"); - unsigned int address = 5; // Mysterious reason for starting at 5 !!! - char RAMdata[6]; - timer.reset(); - timer.start(); - for (int i=0; i<5462; i++) { // Mysterious number 5462 is 0x8000 / 6 - rounded up !!! - T5ReadRAM(RAMdata, address); - address += 6; - for (int j=0; j<6; j++) { - if (((i*6) + j) < T5RAMSIZE) - fputc(RAMdata[j],fp); - } - } - timer.stop(); - printf("Getting the RAM Data took %f seconds.\r\n",timer.read()); - fclose(fp); - return TRUE; -} - -// -// Trionic5SendBootLoader -// -// Sends a 'bootloader' file, booty.s19 to the T5 ECU. -// The 'bootloader' is stored on the mbed 'local' file system 'disk' and must be in S19 format. -// -// The 'bootloader' is then able to dump or reFLASH the T5 ECU FLASH chips - this is the whole point of the exercise :-) -// -// Sending the 'bootloader' to the T5 ECU takes just over 1 second. -// -// inputs: none -// return: bool TRUE if all went OK, -// FALSE if the 'bootloader' wasn't sent for some reason. -// -bool Trionic5SendBootLoader() { - FILE *fp = fopen("/local/MyBooty.S19", "r"); // Open "booty.s19" on the local file system for reading - if (!fp) return FALSE; - int c = 0; // for some reason fgetc returns an int instead of a char - int count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal - int asize = 0; // 2,3 or 4 bytes in address - unsigned int address = 0; // address to put S-record - int checksum = 0; // checksum check at the end of each S-record line - char msg[8]; // Construct the bootloader frame for uploading - bool sent = FALSE; - - timer.reset(); - timer.start(); - while (!sent) { - - do c = fgetc (fp); // get characters until we get an 'S' (throws away \n,\r characters and other junk) - while (c != 'S' && c != EOF); -// if (c == EOF) return '\a'; - c = fgetc(fp); // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) -// if ((c = fgetc(fp)) == EOF) return '\a'; // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) - switch (c) { - case '0': - break; // Skip over S0 header record - - case '1': - case '2': - case '3': - asize = 1 + c - '0'; // 2, 3 or 4 bytes for address - address = 0; -// get the number of bytes (in ascii format) in this S-record line -// there must be at least the address and the checksum so return with an error if less than this! - if ((c = SRecGetByte(fp)) < (asize + 1)) break; -// if ((c = SRecGetByte(fp)) < 3) return '\a'; - count = c; - checksum = c; -// get the address - for (int i=0; i<asize; i++) { - c = SRecGetByte(fp); - checksum += c; - address <<= 8; - address |= c; - count--; - } -// send a bootloader address message - T5SendBootAddress(address, (count-1)); -// T5WaitResponsePrint(); - T5WaitResponse(); -// get and send the bootloader frames for this S-record -// NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes -// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes -// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame. - for (int i=0; i<count-1; i++) { - c = SRecGetByte(fp); - checksum += c; - msg[1+(i%7)] = c; - if (i%7 == 0) msg[0]=i; // set the index number - if ((i%7 == 6) || (i == count - 2)) { - T5SendBootFrame(msg); -// T5WaitResponsePrint(); - T5WaitResponse(); - } - } -// get the checksum - if (((checksum += SRecGetByte(fp)) | 0xFF) != 0xFF) break; -// if ((checksum += SRecGetByte(fp)) != 0xff) return '\a'; - break; - - case '5': - break; // Skip over S5 record types - - case '7': - case '8': - case '9': - asize = 11 - (c - '0'); // 2, 3 or 4 bytes for address -// get the number of bytes (in ascii format) in this S-record line there must be just the address and the checksum -// so return with an error if other than this! - printf("Starting the bootloader, "); - if ((c = SRecGetByte(fp)) != (asize + 1)) break; -// if ((c = SRecGetByte(fp)) < 3) return '\a'; - printf("so far so good"); - checksum = c; -// get the address - for (int i=0; i<asize; i++) { - c = SRecGetByte(fp); - checksum += c; - address <<= 8; - address |= c; - } - printf("calculated the address, "); -// get the checksum -// if (((checksum += SRecGetByte(fp)) | 0xFF) != 0xFF) break; -// if ((checksum += SRecGetByte(fp)) != 0xff) return '\a'; - printf("checksum is OK, "); - T5StartBootLoader(address); -// T5WaitResponsePrint(); - sent = TRUE; - printf("and we're done :-) \r\n"); - break; - -// Some kind of invalid S-record type so break - default: - printf("oops - didn't recognise that S-Record \r\n"); - return FALSE; -// return SREC_FORMAT; - } - } - timer.stop(); - printf("Uploading and starting the bootloader took %f seconds. \r\n",timer.read()); - fclose(fp); - return TRUE; -} - -// -// Trionic5GetChecksum -// -// Calculates the checksum of the FLASH in the T5 ECU. -// The 'bootloader', booty.s19, must be loaded before this function can be used. -// The 'bootloader' actually calculates the checksum and compares it with the -// value stored in the 'header' region at the end of the FLASH. -// -// The bootloader sends a single CAN message with the result e.g. -// w00C8C800CAFEBABE0808 -// 00C - T5 response messages have an CAN id of 00C -// 8 - All T5 messages have a message length of 8 bytes -// C8 - This is the checksum message type -// 00 - 00 means OK, the checksum calculation matches the stored value which in this case is: -// CAFEBABE - lol :-) -// -// w00C8C801FFFFFFFF0808 -// 01 - 01 means calculated value doesn't matched the stored value -// FFFFFFFF - in this case the stored value is FFFFFFFF - the chips might be erased -// -// Calculating the checksum takes a little under 2 seconds. -// -// inputs: none -// return: bool TRUE if all went OK, -// -bool Trionic5GetChecksum() { - timer.reset(); - timer.start(); - T5BootCSumCmnd(); - T5WaitResponsePrint(); - timer.stop(); - printf("T5 ECU took took %f seconds to calculate it's checksum.\r\n",timer.read()); - return TRUE; -} - -// -// Trionic5BootloaderReset -// -// Exits the Bootloader and restart the T5 ECU -// -// inputs: none -// outputs: bool TRUE if all went OK. -// -bool Trionic5BootloaderReset() { - T5BootResetCmnd(); - T5WaitResponsePrint(); - return TRUE; -} - -// -// Trionic5GetChipTypes -// -// Gets the FLASH chip type fitted. -// -// NOTE the bootloader must be loaded in order to use this function. -// -// CAN messages from the T5 ECU with FLASH data look like this: -// -// C9,00,aa,aa,aa,aa,mm,dd, -// -// C9 lets us know its a FLASH id message -// -// aa,aa,aa,aa is the FLASH start address which we can use to work out if this is a T5.2 or T5.5 ECU -// 0x00020000 - T5.2 -// 0x00040000 - T5.5 -// -// mm = Manufacturer id. These can be: -// 0x89 - Intel -// 0x31 - CSI/CAT -// 0x01 - AMD -// 0x1F - Atmel -// -// dd = Device id. These can be: -// 0xB8 - Intel _or_ CSI 28F512 (Fiited by Saab in T5.2) -// 0xB4 - Intel _or_ CSI 28F010 (Fitted by Saab in T5.5) -// 0x25 - AMD 28F512 (Fiited by Saab in T5.2) -// 0xA7 - AMD 28F010 (Fitted by Saab in T5.5) -// 0x20 - AMD 29F010 (Some people have put these in their T5.5) -// 0x5D - Atmel 29C512 (Some people mave have put these in their T5.2) -// 0xD5 - Atmel 29C010 (Some people have put these in their T5.5) -// -// mm = 0xFF, dd == 0xF7 probably means that the programming voltage isn't right. -// -// Finding out which ECU type and FLASH chips are fitted takes under a second. -// -// inputs: none -// return: bool TRUE if all went OK. -// -bool Trionic5GetChipTypes() { - timer.reset(); - timer.start(); - T5BootFLASHType(); - T5WaitResponsePrint(); - timer.stop(); - printf("Getting the FLASH chip id took %f seconds.\r\n",timer.read()); - return TRUE; -} - -// -// Trionic5EraseFLASH -// -// Erases the FLASH Chips. -// -// NOTE the bootloader must be loaded in order to use this function. -// -// CAN messages from the T5 ECU with FLASH erase command look like this: -// -// C0,cc,08,08,08,08,08,08 -// -// C0 tells us this is a response to the FLASH erase command. -// -// cc is a code that tells us what happened: -// 00 - FLASH was erased OK -// 01 - Could not erase FLASH chips to 0xFF -// 02 - Could not write 0x00 to 28F FLASH chips -// 03 - Unrecognised FLASH chip type (or maybe programming voltage isn't right) -// 04 - Intel chips found, but unrecognised type -// 05 - AMD chips found, but unrecognised type -// 06 - CSI/Catalyst chips found, but unrecognised type -// 07 - Atmel chips found - Atmel chips don't need to be erased -// -// Erasing 28F type FLASH chips takes around 22 seconds. 29F chips should be erased much more quickly. -// -// inputs: none -// return: bool TRUE if all went OK. -// -bool Trionic5EraseFLASH() { - timer.reset(); - timer.start(); - T5BootEraseCmnd(); - T5WaitResponsePrint(); - timer.stop(); - printf("Erasing the FLASH took %f seconds.\r\n",timer.read()); - return TRUE; -} - -// -// Trionic5DumpFLASH -// -// Dumps the FLASH chip BIN file, original.hex to the mbed 'disk' -// -// NOTE the bootloader must be loaded in order to use this function. -// -// CAN messages from the T5 ECU with FLASH data look like this: -// -// A6,mm,dd,dd,dd,dd,08,08 -// -// A6 lets us know its a FLASH data message -// mm tells us if there is any more data -// mm == 04 means at least 4 more bytes to come -// mm == 00 means that these are the last FLASH data bytes -// dd,dd,dd,dd are 4 FLASH data bytes -// The last 2 bytes are 08,08 they aren't and don't meean anything -// (It would be more efficient to dump 6 bytes at a time because less -// CAN messages would be needed but it was easier to write the -// bootloader to send just 4 bytes so that's what I did) -// -// Dumping FLASH chips in a T5.5 ECU takes around 88 seconds. Dumping T5.2 ECUs should take about half of this time -// -// inputs: none -// return: bool TRUE if all went OK. -// -bool Trionic5DumpFLASH() { - printf("getting FLASH BIN file\r\n"); - FILE *fp = fopen("/local/original.hex", "w"); // Open "original.hex" on the local file system for writing - if (!fp) return FALSE; - printf("opened FLASH BIN file\r\n"); - char FLASHdata[8]; - timer.reset(); - timer.start(); -// int count = 0; - do { - T5BootDumpFLASHCmnd(); -// T5WaitResponsePrint(); - T5WaitFLASH(FLASHdata); - for (int j=0; j<4; j++) { - fputc(FLASHdata[j+2],fp); -// count++; - } - } while (FLASHdata[1] != 0); - timer.stop(); -// printf("count = 0x%x\r\n", count); - printf("Getting the FLASH BIN took %f seconds.\r\n",timer.read()); - fclose(fp); - return TRUE; -} - - -// -// Trionic5DumpFLASH2 -// -// Gets the adaption data from the T5's SRAM. -// The adaption data is stored in a hex file, adaption.hex, on the mbed 'local' file system 'disk'. -// -// Reading the Adaption data from SRAM takes about 16 seconds. -// -// inputs: none -// return: bool TRUE if all went OK, FALSE if there was an error. -// -bool Trionic5DumpFLASH2() { - printf("getting FLASH BIN file\r\n"); - FILE *fp = fopen("/local/original.hex", "w"); // Open "adaption.hex" on the local file system for writing - if (!fp) return FALSE; - printf("opened FLASH BIN file\r\n"); - unsigned int address = 0x40005; // Mysterious reason for starting at 5 !!! - char FLASHdata[6]; - timer.reset(); - timer.start(); - for (int i=0; i<43690; i++) { // Mysterious number 43690 is 0x40000 / 6 - T5ReadFLASH(FLASHdata, address); - address += 6; - for (int j=0; j<6; j++) { - fputc(FLASHdata[j],fp); - } - } - address = 0x7FFFF; - T5ReadFLASH(FLASHdata, address); - for (int j=0; j<4; j++) { - fputc(FLASHdata[j+2],fp); - } - timer.stop(); - printf("Getting the FLASH BIN took %f seconds.\r\n",timer.read()); - fclose(fp); - return TRUE; -} - -// -// Trionic5SendFLASHUpdate -// -// Sends a FLASH update file, modified.s19 to the T5 ECU. -// The FLASH update file is stored on the local file system and must be in S19 format. -// -// FLASHing a T5.5 ECU takes around 90 seconds. FLASHing T5.2 ECUs should take about half of this time -// -// inputs: none -// return: bool TRUE if all went OK, -// FALSE if the FLASH update failed for some reason. -// -bool Trionic5SendFLASHUpdate() { - FILE *fp = fopen("/local/modified.s19", "r"); // Open "modified.s19" on the local file system for reading - if (!fp) return FALSE; - printf("Opened MODIFIED.S19 "); - int c = 0; // for some reason fgetc returns an int instead of a char - int count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal - int asize = 0; // 2,3 or 4 bytes in address - unsigned int address = 0; // address to put S-record - int checksum = 0; // checksum check at the end - char msg[8]; // Construct the bootloader frame for uploading - bool sent = FALSE; - - timer.reset(); - timer.start(); - while (!sent) { - - do c = fgetc (fp); // get characters until we get an 'S' (throws away \n,\r characters and other junk) - while (c != 'S' && c != EOF); -// if (c == EOF) return '\a'; - c = fgetc(fp); // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) -// if ((c = fgetc(fp)) == EOF) return '\a'; // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) - switch (c) { - case '0': - break; // Skip over S0 header record - - case '1': - case '2': - case '3': - asize = 1 + c - '0'; // 2, 3 or 4 bytes for address - address = 0; -// get the number of bytes (in ascii format) in this S-record line -// there must be at least the address and the checksum so return with an error if less than this! - if ((c = SRecGetByte(fp)) < (asize + 1)) break; -// if ((c = SRecGetByte(fp)) < 3) return '\a'; - count = c; - checksum = c; -// get the address - for (int i=0; i<asize; i++) { - c = SRecGetByte(fp); - checksum += c; - address <<= 8; - address |= c; - count--; - } - address += 0x40000; // Only for T5.5 at the moment !!! -// send a bootloader address message - T5SendBootAddress(address, (count-1)); -// T5WaitResponsePrint(); - T5WaitResponse(); -// get and send the bootloader frames for this S-record -// NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes -// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes -// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame. - for (int i=0; i<count-1; i++) { - c = SRecGetByte(fp); - checksum += c; - msg[1+(i%7)] = c; - if (i%7 == 0) msg[0]=i; // set the index number - if ((i%7 == 6) || (i == count - 2)) { - T5SendBootFrame(msg); -// T5WaitResponsePrint(); - T5WaitResponse(); - } - } -// get the checksum - if (((checksum += SRecGetByte(fp)) | 0xFF) != 0xFF) break; -// if ((checksum += SRecGetByte(fp)) != 0xff) return '\a'; - break; - - case '5': - break; // Skip over S5 record types - - case '7': - case '8': - case '9': - sent = TRUE; - printf("and we're done :-) \r\n"); - break; - -// Some kind of invalid S-record type so break - default: - printf("oops - didn't recognise that S-Record \r\n"); - return FALSE; -// return SREC_FORMAT; - } - } - timer.stop(); - printf("Uploading the FLASH update file took %f seconds. \r\n",timer.read()); - fclose(fp); - return TRUE; -} - -// -// Trionic5SendC3Message -// -// Sends a C3 Message to the T5 ECU. The reply should contain the last used FLASH address -// which is always 0x0007FFFF -// -// inputs: none -// return: bool TRUE if all went OK, -// -bool Trionic5SendC3Message() { - T5BootC3Command(); - T5WaitResponsePrint(); - printf("The Last used FLASH address message is:\r\n"); - return TRUE; -}
--- a/Trionic5.h Wed May 19 12:39:18 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ - -// Trionic5.h - information and definitions needed for doing things with the T5 ECU - -#include "mbed.h" -#include "CAN.h" -#include "strings.h" -#include "T5Utils.h" -#include "SRecUtils.h" - -#define CR 0x0D -#define NL 0x0A - -#define T5SYMBOLS 'S' -#define T5VERSION 's' -#define T5WRITE 'W' - -#define T5RAMSIZE 0x8000 // T5 ECU has 32 kbytes of RAM 0x8000 = 32,768 (same as MC68332 clock speed!?!) -#define T55FLASHSIZE 0x40000 // T5 ECU has 32 kbytes of RAM 0x8000 = 32,768 (same as MC68332 clock speed!?!) -#define T52FLASHSIZE 0x20000 // T5 ECU has 32 kbytes of RAM 0x8000 = 32,768 (same as MC68332 clock speed!?!) - -extern void Trionic5(); - -void Trionic5ShowHelp(); -bool Trionic5ShowCANMessage(); -bool Trionic5GetSymbolTable(); -bool Trionic5GetVersion(); -bool Trionic5GetAdaptionData(); -bool Trionic5SendBootLoader(); -bool Trionic5GetChecksum(); -bool Trionic5BootloaderReset(); -bool Trionic5GetChipTypes(); -bool Trionic5EraseFLASH(); -bool Trionic5DumpFLASH(); -bool Trionic5DumpFLASH2(); -bool Trionic5SendFLASHUpdate(); -bool Trionic5SendC3Message();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bdm.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,567 @@ +/******************************************************************************* + +bdm.cpp +(c) 2010 by Sophie Dexter + +BDM functions for Just4Trionic by Just4pLeisure + +A derivative work based on: +//----------------------------------------------------------------------------- +// Firmware for USB BDM v2.0 +// (C) johnc, 2009 +// $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 "bdm.h" + +// constants +#define CMD_BUF_LENGTH 32 ///< command buffer size + +// LED constants and macros +#define LED_ONTIME 5 ///< LED 'on' time, ms +#define LED_TCNT (255 - (unsigned char)((unsigned long)(LED_ONTIME * 1000L) \ + / (1000000L / (float)((unsigned long)XTAL_CPU / 1024L)))) + +// command characters +#define CMDGROUP_ADAPTER 'a' ///< adapter commands +#define CMD_VERSION 'v' ///< firmware version +#define CMD_PINSTATUS 's' ///< momentary status of BDM pins +#define CMD_BKPTLOW '1' ///< pull BKPT low +#define CMD_BKPTHIGH '2' ///< pull BKPT high +#define CMD_RESETLOW '3' ///< pull RESET low +#define CMD_RESETHIGH '4' ///< pull RESET high + +#define CMDGROUP_MCU 'c' ///< target MCU management commands +#define CMD_STOPCHIP 'S' ///< stop +#define CMD_RESETCHIP 'R' ///< reset +#define CMD_RUNCHIP 'r' ///< run from given address +#define CMD_RESTART 's' ///< restart +#define CMD_STEP 'b' ///< step + +#define CMDGROUP_FLASH 'f' +#define CMD_GETVERIFY 'v' ///< gets verification status +#define CMD_SETVERIFY 'V' ///< sets verification on/off +#define CMD_DUMP 'd' ///< dumps memory contents +#define CMD_ERASE 'E' ///< erase entire flash memory +#define CMD_WRITE 'w' ///< writes to flash memory + +#define CMDGROUP_MEMORY 'm' ///< target MCU memory commands +#define CMD_READBYTE 'b' ///< read byte from memory +#define CMD_READWORD 'w' ///< read word (2 bytes) from memory +#define CMD_READLONG 'l' ///< read long word (4 bytes) from memory +#define CMD_DUMPBYTE 'z' ///< dump byte from memory +#define CMD_DUMPWORD 'x' ///< dump word from memory +#define CMD_DUMPLONG 'c' ///< dump long word from memory +#define CMD_WRITEBYTE 'B' ///< write byte to memory +#define CMD_WRITEWORD 'W' ///< write word to memory +#define CMD_WRITELONG 'L' ///< write long word to memory +#define CMD_FILLBYTE 'f' ///< fill byte in memory +#define CMD_FILLWORD 'F' ///< fill word in memory +#define CMD_FILLLONG 'M' ///< fill long word in memory + +#define CMDGROUP_REGISTER 'r' ///< register commands +#define CMD_READSYSREG 'r' ///< read system register +#define CMD_WRITESYSREG 'W' ///< write system register +#define CMD_READADREG 'a' ///< read A/D register +#define CMD_WRITEADREG 'A' ///< write A/D register + +#define CMDGROUP_TRIONIC 'T' +#define CMD_TRIONICDUMP 'D' ///< dumps memory contents +#define CMD_TRIONICWRITE 'F' ///< writes to flash memory + +// static variables +static char cmd_buffer[CMD_BUF_LENGTH]; ///< command string buffer +static uint32_t cmd_addr; ///< address (optional) +static uint32_t cmd_value; ///< value (optional) +static uint32_t cmd_result; ///< result + +// private functions +uint8_t execute_bdm_cmd(); + +void bdm_show_help(); +void bdm_show_full_help(); + +// command argument macros +#define CHECK_ARGLENGTH(len) \ + if (cmd_length != len + 2) \ + return TERM_ERR + +#define GET_NUMBER(target, offset, len) \ + if (!ascii2int(target, cmd_buffer + 2 + offset, len)) \ + return TERM_ERR + + +void bdm() { + + bdm_show_help(); + // set up LED pins +// SETBIT(LED_DIR, _BV(LED_ERR) | _BV(LED_ACT)); + // set up USB_RD and USB_WR pins +// SETBIT(USB_RXTX_DIR, _BV(USB_RD) | _BV(USB_WR)); + + // enable interrupts +// sei(); + + // load configuration from EEPROM +// verify_flash = eeprom_read_byte(&ee_verify); + +// Set some initial values to help with checking if the BDM connector is plugged in + PIN_PWR.mode(PullDown); + PIN_NC.mode(PullUp); + PIN_DS.mode(PullUp); + PIN_FREEZE.mode(PullUp); + PIN_DSO.mode(PullUp); + + verify_flash = true; + + // main loop + *cmd_buffer = '\0'; + char ret; + char rx_char; + while (true) { + // read chars from USB + if (pc.readable()) { + // turn Error LED off for next command + led4 = 0; + rx_char = pc.getc(); + switch (rx_char) { + // 'ESC' key to go back to mbed Just4Trionic 'home' menu + case '\e': + reset_chip(); + return; + // end-of-command reached + case TERM_OK : + // execute command and return flag via USB + ret = execute_bdm_cmd(); + pc.putc(ret); + // reset command buffer + *cmd_buffer = '\0'; + // light up LED +// ret == TERM_OK ? led_on(LED_ACT) : led_on(LED_ERR); + ret == TERM_OK ? led3 = 1 : led4 = 1; + break; + // another command char + default: + // store in buffer if space permits + if (StrLen(cmd_buffer) < CMD_BUF_LENGTH - 1) { + StrAddc(cmd_buffer, rx_char); + } + break; + } + } + } +} + +//----------------------------------------------------------------------------- +/** + Executes a command and returns result flag (does not transmit the flag + itself). + + @return command flag (success / failure) +*/ +uint8_t execute_bdm_cmd() { + uint8_t cmd_length = strlen(cmd_buffer); + char cmd = *(cmd_buffer + 1); + + // command groups + switch (*cmd_buffer) { + // adapter commands + case CMDGROUP_ADAPTER: + CHECK_ARGLENGTH(0); + switch (cmd) { + // get firmware version + case CMD_VERSION: + printf("%02x", FW_VERSION_MAJOR); + printf("%02x", FW_VERSION_MINOR); + return TERM_OK; + + // get momentary status of BDM pins 0...5 (for debugging) + case CMD_PINSTATUS: +// printf("%02x", (BDM_PIN & 0x3f)); + printf("PWR %d, ", PIN_PWR.read()); + printf("NC %d, ", PIN_NC.read()); + printf("DS %d, ", PIN_DS.read()); + printf("FREEZE %d, ", PIN_FREEZE.read()); + printf("DSO %d, ", PIN_DSO.read()); + return TERM_OK; + + // pull BKPT low + case CMD_BKPTLOW: + return bkpt_low(); + + // pull BKPT high + case CMD_BKPTHIGH: + return bkpt_high(); + + // pull RESET low + case CMD_RESETLOW: + return reset_low(); + + // pull RESET high + case CMD_RESETHIGH: + return reset_high(); + } + break; + + // MCU management + case CMDGROUP_MCU: + switch (cmd) { + // stop target MCU + case CMD_STOPCHIP: + return stop_chip(); + + // reset target MCU + case CMD_RESETCHIP: + return reset_chip(); + + // run target MCU from given address + case CMD_RUNCHIP: + CHECK_ARGLENGTH(8); + GET_NUMBER(&cmd_addr, 0, 8); + return run_chip(&cmd_addr); + + // restart + case CMD_RESTART: + return restart_chip(); + + // step + case CMD_STEP: + return step_chip(); + } + break; + + // Trionic dumping and flashing + case CMDGROUP_FLASH: + switch (cmd) { + // get verification flag + case CMD_GETVERIFY: + CHECK_ARGLENGTH(0); + printf("%02x", (uint8_t)verify_flash); + return TERM_OK; + + // set verification flag + case CMD_SETVERIFY: + CHECK_ARGLENGTH(2); + GET_NUMBER(&cmd_addr, 0, 2); + verify_flash = (bool)cmd_addr; +// eeprom_write_byte(&ee_verify, verify_flash); + return TERM_OK; + + // dump flash contents as block + case CMD_DUMP: + CHECK_ARGLENGTH(16); + GET_NUMBER(&cmd_addr, 0, 8); + GET_NUMBER(&cmd_value, 8, 8); + return dump_flash(&cmd_addr, &cmd_value); + + // erase entire flash memory + case CMD_ERASE: + CHECK_ARGLENGTH(22); + GET_NUMBER(&cmd_addr, 6, 8); + GET_NUMBER(&cmd_value, 14, 8); + return erase_flash(cmd_buffer + 2, &cmd_addr, &cmd_value); + + // write data block to flash memory + case CMD_WRITE: + CHECK_ARGLENGTH(14); + GET_NUMBER(&cmd_addr, 6, 8); + return write_flash(cmd_buffer + 2, &cmd_addr); + } + break; + + // memory + case CMDGROUP_MEMORY: + if (cmd != CMD_FILLBYTE && cmd != CMD_FILLWORD && + cmd != CMD_FILLLONG && cmd != CMD_DUMPBYTE && cmd != CMD_DUMPWORD && + cmd != CMD_DUMPLONG) { + // get memory address + if (cmd_length < 10 || !ascii2int(&cmd_addr, cmd_buffer + 2, 8)) { + // broken parametre + return TERM_ERR; + } + + // get optional value + if (cmd_length > 10 && + !ascii2int(&cmd_value, cmd_buffer + 10, cmd_length - 10)) { + // broken parametre + return TERM_ERR; + } + } + + switch (cmd) { + // read byte + case CMD_READBYTE: + if (cmd_length != 10 || + memread_byte((uint8_t*)(&cmd_result), &cmd_addr) != TERM_OK) { + return TERM_ERR; + } + printf("%02x", (uint8_t)cmd_result); + return TERM_OK; + + // read word + case CMD_READWORD: + if (cmd_length != 10 || + memread_word((uint16_t*)(&cmd_result), &cmd_addr) != TERM_OK) { + return TERM_ERR; + } + printf("%04X", (uint16_t)cmd_result); + return TERM_OK; + + // read long word + case CMD_READLONG: + if (cmd_length != 10 || + memread_long(&cmd_result, &cmd_addr) != TERM_OK) { + return TERM_ERR; + } + printf("%08X", cmd_result); + return TERM_OK; + + // dump byte + case CMD_DUMPBYTE: + if (cmd_length != 2 || + memdump_byte((uint8_t*)(&cmd_result)) != TERM_OK) { + return TERM_ERR; + } + printf("%02x", (uint8_t)cmd_result); + return TERM_OK; + + // dump word + case CMD_DUMPWORD: + if (cmd_length != 2 || + memdump_word((uint16_t*)(&cmd_result)) != TERM_OK) { + return TERM_ERR; + } + printf("%04X", (uint16_t)cmd_result); + return TERM_OK; + + // dump long word + case CMD_DUMPLONG: + if (cmd_length != 2 || + memdump_long(&cmd_result) != TERM_OK) { + return TERM_ERR; + } + printf("%08X", cmd_result); + return TERM_OK; + + // write byte + case CMD_WRITEBYTE: + return (cmd_length == 12 && + memwrite_byte(&cmd_addr, cmd_value) == TERM_OK) ? + TERM_OK : TERM_ERR; + + // write word + case CMD_WRITEWORD: + return (cmd_length == 14 && + memwrite_word(&cmd_addr, cmd_value) == TERM_OK) ? + TERM_OK : TERM_ERR; + + // write long word + case CMD_WRITELONG: + return (cmd_length == 18 && + memwrite_long(&cmd_addr, &cmd_value) == TERM_OK) ? + TERM_OK : TERM_ERR; + + // fill byte + case CMD_FILLBYTE: + if (cmd_length != 4 || !ascii2int(&cmd_value, cmd_buffer + 2, 2)) { + return TERM_ERR; + } + return (memfill_byte(cmd_value)); + + // fill word + case CMD_FILLWORD: + if (cmd_length != 6 || !ascii2int(&cmd_value, cmd_buffer + 2, 4)) { + return TERM_ERR; + } + return (memfill_word(cmd_value)); + + // fill long word + case CMD_FILLLONG: + if (cmd_length != 10 || !ascii2int(&cmd_value, cmd_buffer + 2, 8)) { + return TERM_ERR; + } + return (memfill_long(&cmd_value)); + } + break; + + // registers + case CMDGROUP_REGISTER: + // get register code + if (cmd_length < 4 || !ascii2int(&cmd_addr, cmd_buffer + 3, 1)) { + // broken parametre + return TERM_ERR; + } + + // get optional value + if (cmd_length > 4 && + !ascii2int(&cmd_value, cmd_buffer + 4, 8)) { + // broken parametre + return TERM_ERR; + } + + switch (cmd) { + // read system register + case CMD_READSYSREG: + if (cmd_length != 4 || + sysreg_read(&cmd_result, (uint8_t)cmd_addr) != TERM_OK) { + return TERM_ERR; + } + printf("%08X", cmd_result); + return TERM_OK; + + // write system register + case CMD_WRITESYSREG: + return (cmd_length == 12 && + sysreg_write((uint8_t)cmd_addr, &cmd_value) == TERM_OK) ? + TERM_OK : TERM_ERR; + + // read A/D register + case CMD_READADREG: + if (cmd_length != 4 || + adreg_read(&cmd_result, (uint8_t)cmd_addr) != TERM_OK) { + return TERM_ERR; + } + printf("%08X", cmd_result); + return TERM_OK; + + // write A/D register + case CMD_WRITEADREG: + return (cmd_length == 12 && + adreg_write((uint8_t)cmd_addr, &cmd_value) == TERM_OK) ? + TERM_OK : TERM_ERR; + } + break; + + // Trionic dumping and flashing + case CMDGROUP_TRIONIC: + + switch (cmd) { + + // dump flash contents to a bin file + case CMD_TRIONICDUMP: + CHECK_ARGLENGTH(0); + return dump_trionic(); + + // write data block to flash memory + case CMD_TRIONICWRITE: + CHECK_ARGLENGTH(0); + return flash_trionic(); + } + + // show help for BDM commands + case 'H': + bdm_show_full_help(); + return TERM_OK; + case 'h': + bdm_show_help(); + return TERM_OK; + default: + bdm_show_help(); + } + + // unknown command + return TERM_ERR; +} + +void bdm_show_help() { + printf("Just4Trionic BDM Command Menu\r\n"); + printf("=============================\r\n"); + printf("TD - and DUMP T5 FLASH BIN file\r\n"); + printf("TF - FLASH the update file to the T5 (and write SRAM)\r\n"); + printf("Tr - Read SRAM adaption (not done).\r\n"); + printf("Tw - Write SRAM adaptation (not done).\r\n"); + printf("\r\n"); + printf("'ESC' - Return to Just4Trionic Main Menu\r\n"); + printf("\r\n"); + printf("h - Show this help menu\r\n"); + printf("\r\n"); + return; +} +void bdm_show_full_help() { + printf("Just4Trionic BDM Command Menu\r\n"); + printf("=============================\r\n"); + printf("TD - and DUMP T5 FLASH BIN file\r\n"); + printf("TF - FLASH the update file to the T5 (and write SRAM)\r\n"); + printf("Tr - Read SRAM adaption (not done).\r\n"); + printf("Tw - Write SRAM adaptation (not done).\r\n"); + printf("\r\n"); + printf("Adapter Commands - a\r\n"); + printf("====================\r\n"); + printf("av - display firmware version\r\n"); + printf("as - display status of BDM pins\r\n"); + printf("a1 - pull BKPT low\r\n"); + printf("a2 - pull BKPT high\r\n"); + printf("a3 - pull RESET low\r\n"); + printf("a4 - pull RESET high\r\n"); + printf("\r\n"); + printf("MCU Management Commands - c\r\n"); + printf("===========================\r\n"); + printf("cS - stop MCU\r\n"); + printf("cR - reset MCU\r\n"); + printf("cr - run from given address\r\n"); + printf(" e.g. crCAFEBABE run from address 0xcafebabe\r\n"); + printf("cs - restart MCU\r\n"); + printf("cb - step MCU\r\n"); + printf("\r\n"); + printf("MCU FLASH Commands - f\r\n"); + printf("======================\r\n"); + printf("fv - gets verification status (always verify)\r\n"); + printf("fV - sets verification on/off (always on)\r\n"); + printf("fd - DUMPs memory contents\r\n"); + printf(" e.g. fdSSSSSSSSEEEEEEEE S...E... start and end addresses\r\n"); + printf(" e.g. fd0000000000020000 to DUMP T5.2\r\n"); + printf(" e.g. fd0000000000040000 to DUMP T5.5\r\n"); + printf(" e.g. fd0000000000080000 to DUMP T7\r\n"); + printf("fE - Erases entire FLASH memory\r\n"); + printf(" e.g. fETTTTTTSSSSSSSSEEEEEEEE T...S...E type, start and end addresses\r\n"); + printf(" e.g. fE28f0100000000000020000 erase 28F512 in T5.2\r\n"); + printf(" e.g. fE28f0100000000000040000 erase 28F010 in T5.5\r\n"); + printf(" e.g. fE29f0100000000000040000 erase 29F010 in T5.5 (addresses not used)\r\n"); + printf(" e.g. fE29f4000000000000080000 erase 29F400 in T7 (addresses not used)\r\n"); + printf("fw - writes to FLASH memory\r\n"); + printf(" Write a batch of long words to flash from a start address\r\n"); + printf(" followed by longwords LLLLLLLL, LLLLLLLL etc\r\n"); + printf(" Send a break character to stop when doneg"); + printf(" e.g. fwTTTTTTSSSSSSSS T...S... type and start address\r\n"); + printf(" e.g. fw28f01000004000 start at address 0x004000 T5.2/5.5\r\n"); + printf(" e.g. fw29f01000004000 start at address 0x004000 T5.5 with 29F010\r\n"); + printf(" e.g. fw29f40000004000 start at address 0x004000 T7\r\n"); + printf("\r\n"); + printf("MCU Memory Commands - m\r\n"); + printf("=======================\r\n"); + printf("mbAAAAAAAA - read byte from memory at 0xaaaaaaaa\r\n"); + printf("mwAAAAAAAA - read word (2 bytes) from memory\r\n"); + printf("mlAAAAAAAA - read long word (4 bytes) from memory\r\n"); + printf("mz - dump byte from the next memory address\r\n"); + printf("mx - dump word from the next memory address\r\n"); + printf("mc - dump long word from the next memory address\r\n"); + printf("mBAAAAAAAADD - write byte 0xdd to memory 0xaaaaaaaa\r\n"); + printf("mWAAAAAAAADDDD - write word 0xdddd to memory 0xaaaaaaaa\r\n"); + printf("mLAAAAAAAADDDDDDD - write long word 0xdddddddd to memory 0xaaaaaaaa\r\n"); + printf("mfDD - fill byte 0xdd to next memory address\r\n"); + printf("mFDDDD - fill word 0xdddd to next memory address\r\n"); + printf("mMDDDDDDDD - fill long word 0xdddddddd to next memory address\r\n"); + printf("\r\n"); + printf("MCU Register Commands - r\r\n"); + printf("=========================\r\n"); + printf("rrRR - read system register RR\r\n"); + printf(" 00 - RPC, 01 - PCC, 0B - SR, 0C - USP, 0D - SSP\r\n"); + printf(" 0e - SFC, 0f - DFC, 08 - ATEMP, 09 - FAR, 0a - VBR\r\n"); + printf("rWRRCAFEBABE - write 0xcafebabe system register RR\r\n"); + printf("raAD - read A/D register 0x00-07 D0-D7, 0x08-15 A0-A7\r\n"); + printf("rAADCAFEBABE - write 0xcafebabe to A/D register \r\n"); + printf("\r\n"); + printf("'ESC' - Return to Just4Trionic Main Menu\r\n"); + printf("\r\n"); + printf("H - Show this help menu\r\n"); + printf("\r\n"); + return; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bdm.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,32 @@ +/******************************************************************************* + +bdm.h +(c) 2010 by Sophie Dexter + +A derivative work based on: +//----------------------------------------------------------------------------- +// Firmware for USB BDM v2.0 +// (C) johnc, 2009 +// $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. + +*******************************************************************************/ + +#ifndef __BDM_H__ +#define __BDM_H__ + +#include "mbed.h" +// +#include "common.h" +#include "bdmcpu32.h" +#include "bdmtrionic.h" + +extern void bdm(); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bdmcpu32.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,1300 @@ +/******************************************************************************* + +bdmcpu32.cpp +(c) 2010 by Sophie Dexter + +Generic 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 "bdmcpu32.h" + +// constants +#define MCU_SETTLE_TIME 10 ///< delay to let MCU switch modes, ms +#define CMD_BIT_COUNT 17 ///< command size, bits + +// BDM commands +#define BDM_NOP 0x0000 ///< no-op +#define BDM_GO 0x0c00 ///< resume execution +#define BDM_WRITE 0x1800 ///< write memory +#define BDM_READ 0x1900 ///< read memory +#define BDM_WSREG 0x2480 ///< write system register +#define BDM_RSREG 0x2580 ///< read system register +#define BDM_RDREG 0x2180 ///< read A/D register +#define BDM_WRREG 0x2080 ///< write A/D register +#define BDM_DUMP 0x1d00 ///< dump memory +#define BDM_FILL 0x1c00 ///< fill memory +#define BDM_CALL 0x0800 ///< function call +#define BDM_RST 0x0400 ///< reset + +// system registers +#define SREG_RPC 0x0 +#define SREG_PCC 0x1 +#define SREG_SR 0xb +#define SREG_USP 0xc +#define SREG_SSP 0xd +#define SREG_SFC 0xe +#define SREG_DFC 0xf +#define SREG_ATEMP 0x8 +#define SREG_FAR 0x9 +#define SREG_VBR 0xa + +// BDM responses +#define BDM_CMDCMPLTE 0x0000ffff ///< command complete +#define BDM_NOTREADY 0x00010000 ///< response not ready +#define BDM_BERR 0x00010001 ///< error +#define BDM_ILLEGAL 0x0001ffff ///< illegal command + +// BDM data sizes +#define BDM_BYTESIZE 0x00 ///< byte +#define BDM_WORDSIZE 0x40 ///< word (2 bytes) +#define BDM_LONGSIZE 0x80 ///< long word (4 bytes) + +// static variables +static uint32_t bdm_response; ///< result of BDM read/write operation + +// private functions +bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr); +//bool bdm_read_overlap(uint32_t* result, uint16_t cmd, const uint32_t* addr, uint16_t next_cmd); +//bool bdm_read_continue(uint32_t* result, const uint32_t* addr, uint16_t next_cmd); +bool bdm_write(const uint32_t* addr, uint16_t cmd, const uint32_t* value); +//bool bdm_write_overlap(const uint32_t* addr, uint16_t cmd, const uint32_t* value, uint16_t next_cmd); +void bdm_clk(uint16_t value, uint8_t num_bits); +void bdm_clear(); + +//----------------------------------------------------------------------------- +/** + Stops target MCU and puts into background debug mode (BDM). + + @return status flag +*/ +uint8_t stop_chip() { + // not connected + if (!IS_CONNECTED) { + return TERM_ERR; + } + + // pull BKPT low to enter background mode (the pin must remain in output mode, + // otherwise the target will pull it high and we'll lose the first DSO bit) + PIN_BKPT.write(0); + // set BPKT pin as output + PIN_BKPT.output(); + + // wait for target MCU to settle + wait_ms(MCU_SETTLE_TIME); + + // check if succeeded + if (!IN_BDM) { + // set BKPT back as input and fail + PIN_BKPT.input(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Forces hardware reset on target MCU and lets it run. + + @return status flag +*/ +uint8_t reset_chip() { + // not connected + if (!IS_CONNECTED) { + return TERM_ERR; + } + + // BKPT pin as input + PIN_BKPT.input(); + // push RESET low + PIN_RESET.write(0); + // RESET pins as output + PIN_RESET.output(); + // wait for MCU to settle + wait_ms(MCU_SETTLE_TIME); + // rising edge on RESET line + PIN_RESET.write(1); + // wait for MCU to settle + wait_ms(MCU_SETTLE_TIME); + + // set RESET as an input again + PIN_RESET.input(); + + // check if succeeded + return IS_RUNNING ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Starts target MCU from the specified address. If address is 0, execution + begins at the current address in program counter. + + @param addr start address + + @return status flag +*/ +uint8_t run_chip(const uint32_t* addr) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // set program counter + if ((*addr > 0) && sysreg_write(SREG_RPC, addr) != TERM_OK) { + return TERM_ERR; + } + // resume MCU + bdm_clk(BDM_GO, CMD_BIT_COUNT); + + // set BKPT back as input + PIN_BKPT.input(); + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Resets target MCU and stops execution on first instruction fetch. + + @return status flag +*/ +uint8_t restart_chip() { + // not connected + if (!IS_CONNECTED) { + return TERM_ERR; + } + + // pull BKPT low to enter background mode (the pin must remain an output, + // otherwise the target will pull it high and we'll lose the first DSO bit) + PIN_BKPT.write(0); + // push RESET low + PIN_RESET.write(0); + // RESET, BKPT pins as outputs + PIN_BKPT.output(); + PIN_RESET.output(); + // wait for target MCU to settle + wait_ms(MCU_SETTLE_TIME); + // rising edge on RESET line + PIN_RESET.write(1); + // wait for target MCU to settle + wait_ms(MCU_SETTLE_TIME); + // set RESET back as an input + PIN_RESET.input(); + + // check if succeeded + if (!IN_BDM) { + // set BKPT back as input and fail + PIN_BKPT.input(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Sends GO command word to target MCU, then triggers breakpoint on first + instruction fetch. + + @return status flag +*/ +uint8_t step_chip() { + // not connected + if (!IS_CONNECTED) { + return TERM_ERR; + } + + // resume MCU + bdm_clk(BDM_GO, CMD_BIT_COUNT); + + // pull BKPT low to enter background mode (the pin must remain an output, + // otherwise the target pulls it high and we lose the first DSO bit) + PIN_BKPT.write(0); + // set BPKT pin as output + PIN_BKPT.output(); + + // wait for target MCU to settle +// delay_ms(MCU_SETTLE_TIME); + wait_ms(MCU_SETTLE_TIME); + + // check if succeeded + if (!IN_BDM) { + // set BKPT back as input and fail + PIN_BKPT.input(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Pulls BKPT pin low. +*/ +uint8_t bkpt_low() { + PIN_BKPT.write(0); + PIN_BKPT.output(); + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Pulls BKPT pin high. +*/ +uint8_t bkpt_high() { + PIN_BKPT.write(1); + PIN_BKPT.output(); + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Pulls RESET pin low. +*/ +uint8_t reset_low() { + PIN_RESET.write(0); + PIN_RESET.output(); + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Pulls RESET pin high. +*/ +uint8_t reset_high() { + PIN_RESET.write(1); + PIN_RESET.output(); + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Returns byte from the specified memory location; MCU must be in + background mode. + + @param result value (out) + @param addr source address + + @return status flag +*/ +uint8_t memread_byte(uint8_t* result, const uint32_t* addr) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // read byte + if (!bdm_read((uint32_t*)result, BDM_READ, addr)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Returns word (2 bytes) from the specified memory location. Address must be + word-aligned and MCU must be in background mode. + + @param result value (out) + @param addr source address + + @return status flag +*/ +uint8_t memread_word(uint16_t* result, const uint32_t* addr) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // read word + if (!bdm_read((uint32_t*)result, BDM_READ + BDM_WORDSIZE, addr)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Returns long word (4 bytes) from the specified memory location. Address + must be word-aligned and target MCU must be in background mode. + + @param result value + @param addr source address + + @return status flag +*/ +uint8_t memread_long(uint32_t* result, const uint32_t* addr) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // read long word + if (!bdm_read(result, BDM_READ + BDM_LONGSIZE, addr)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Dumps byte from the specified memory location; MCU must be in background + mode. Any memread_*() function must be called beforehand to set the + initial address. + + @param value result (out) + + @return status flag +*/ +uint8_t memdump_byte(uint8_t* result) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // dump byte + if (!bdm_read((uint32_t*)result, BDM_DUMP, NULL)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + dumps word from the specified memory location; MCU must be in background + mode. Any memread_*() function must be called beforehand to set the + initial address. + + @param value result (out) + + @return status flag +*/ +uint8_t memdump_word(uint16_t* result) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // dump word + if (!bdm_read((uint32_t*)result, BDM_DUMP + BDM_WORDSIZE, NULL)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Dumps long word from the specified memory location; MCU must be in + background mode. Any memread_*() function must be called beforehand to set + the initial address. + + @param value result (out) + + @return status flag +*/ +uint8_t memdump_long(uint32_t* result) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // dump long word + if (!bdm_read(result, BDM_DUMP + BDM_LONGSIZE, NULL)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Writes byte to the specified memory location; MCU must be in background + mode. + + @param addr destination address + @param value value + + @return status flag +*/ +uint8_t memwrite_byte(const uint32_t* addr, uint8_t value) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // write byte + if (!bdm_write(addr, BDM_WRITE, (uint32_t*)&value)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Writes word to the specified memory location. Address must be word-aligned + and MCU must be in background mode. + + @param addr memory address + @param value value + + @return status flag +*/ +uint8_t memwrite_word(const uint32_t* addr, uint16_t value) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // write word + if (!bdm_write(addr, BDM_WRITE + BDM_WORDSIZE, (uint32_t*)&value)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Writes long word to the specified memory location. Address must be + word-aligned and target MCU must be in background mode. + + @param addr memory address + @param value value + + @return status flag +*/ +uint8_t memwrite_long(const uint32_t* addr, const uint32_t* value) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // write long word + if (!bdm_write(addr, BDM_WRITE + BDM_LONGSIZE, value)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Writes byte to the current memory location; MCU must be in background + mode. Any memwrite_*() function must be called beforehand to set the + current address. + + @param value value + + @return status flag +*/ +uint8_t memfill_byte(uint8_t value) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // fill byte + if (!bdm_write(NULL, BDM_FILL, (uint32_t*)&value)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Writes word to the specified memory location; MCU must be in background + mode. Any memwrite_*() function must be called beforehand to set the + initial address. + + @param value value + + @return status flag +*/ +uint8_t memfill_word(uint16_t value) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // fill word + if (!IN_BDM || !bdm_write(NULL, BDM_FILL + BDM_WORDSIZE, (uint32_t*)&value)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Writes long word to the specified memory location; MCU must be in background + mode. Any memwrite_*() function must be called beforehand to set the + initial address. + + @param value value + + @return status flag +*/ +uint8_t memfill_long(const uint32_t* value) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // fill long word + if (!bdm_write(NULL, BDM_FILL + BDM_LONGSIZE, value)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Issues a read byte command to MCU. + + @param addr address (optional) + + @return status flag +*/ +uint8_t memread_byte_cmd(const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + + // write command code + if (!bdm_command(BDM_READ + BDM_BYTESIZE)) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Issues a read word command to MCU. + + @param addr address (optional) + + @return status flag +*/ +uint8_t memread_word_cmd(const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + + // write command code + bdm_clk(BDM_READ + BDM_WORDSIZE, CMD_BIT_COUNT); + if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Issues a read long command to MCU. + + @param addr address (optional) + + @return status flag +*/ +uint8_t memread_long_cmd(const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + + // write command code + bdm_clk(BDM_READ + BDM_LONGSIZE, CMD_BIT_COUNT); + if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + + return TERM_OK; +} +//----------------------------------------------------------------------------- +/** + Issues a write byte command to MCU. + + @param addr address (optional) + + @return status flag +*/ +uint8_t memwrite_byte_cmd(const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + + // write command code + if (!bdm_command(BDM_WRITE + BDM_BYTESIZE)) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Issues a write word command to MCU. + + @param addr address (optional) + + @return status flag +*/ +uint8_t memwrite_word_cmd(const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + + // write command code + bdm_clk(BDM_WRITE + BDM_WORDSIZE, CMD_BIT_COUNT); + if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Issues a write long command to MCU. + + @param addr address (optional) + + @return status flag +*/ +uint8_t memwrite_long_cmd(const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + + // write command code + bdm_clk(BDM_WRITE + BDM_LONGSIZE, CMD_BIT_COUNT); + if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Gets a byte from the MCU (follows a previously sent read or dump word cmd) + Sends a READ_BYTE command so that commands overlap + + @param result read result (out) + addr address (optional) + + @return status flag +*/ +uint8_t memread_read_byte(uint8_t* result, const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + // receive the response byte + return (bdm_get ((uint32_t*)result, BDM_BYTESIZE, BDM_READ + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Gets a byte from the MCU (follows a previously sent read or dump word cmd) + Sends a WRITE_BYTE command so that commands overlap + + @param result read result (out) + addr address (optional) + + @return status flag +*/ +uint8_t memread_write_byte(uint8_t* result, const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + // receive the response byte + return (bdm_get((uint32_t*)result, BDM_BYTESIZE, BDM_WRITE + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Gets a byte from the MCU (follows a previously sent read or dump word cmd) + Sends a BDM_NOP command to end a sequence of overlapping commands + + @param result read result (out) + addr address (optional) + + @return status flag +*/ +uint8_t memread_nop_byte(uint8_t* result, const uint32_t* addr) { + + if (!IN_BDM) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + // receive the response byte + return (bdm_get((uint32_t*)result, BDM_BYTESIZE, BDM_NOP)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Writes a byte to the MCU (follows a previously sent write or fill word cmd) + Sends a WRITE_BYTE command so that commands overlap + + @param addr address (optional) + value value to write + + @return status flag +*/ +uint8_t memwrite_write_byte(const uint32_t* addr, uint8_t value) { + + if (!IN_BDM) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + // write the value + if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR; + // wait until MCU responds + return (bdm_ready(BDM_WRITE + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Writes a byte to the MCU (follows a previously sent write or fill word cmd) + Sends a READ_BYTE command so that commands overlap + + @param addr address (optional) + value value to write + + @return status flag +*/ +uint8_t memwrite_read_byte(const uint32_t* addr, uint8_t value) { + + if (!IN_BDM) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + // write the value + if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR; + // wait until MCU responds + return (bdm_ready(BDM_READ + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Writes a byte to the MCU (follows a previously sent write or fill word cmd) + Sends a BDM_NOP command to end a sequence of overlapping commands + + @param addr address (optional) + value value to write + + @return status flag +*/ +uint8_t memwrite_nop_byte(const uint32_t* addr, uint8_t value) { + + if (!IN_BDM) return TERM_ERR; + // write the optional address + if (addr) { + if(!bdm_address(addr)) return TERM_ERR; + } + // write the value + if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR; + // wait until MCU responds + return (bdm_ready(BDM_NOP)) ? TERM_OK : TERM_ERR; +} + + +//----------------------------------------------------------------------------- +/** + Writes 2 words to the same address + The BDM commands are overlapped to make things a bit faster + A BDM_NOP command is then sent to end the sequence of overlapping commands + + @param addr address + value1, 2 values to write + + @return status flag +*/ +uint8_t memwrite_word_write_word(const uint32_t* addr, const uint16_t value1, const uint16_t value2) { + + if (!IN_BDM) return TERM_ERR; + + // write command code + if (!bdm_command(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR; + // write the address + if (!bdm_address(addr)) return TERM_ERR; + // write the first value + if (!bdm_put((uint32_t*)&value1, BDM_WORDSIZE)) return TERM_ERR; + // wait until MCU responds and overlap the next write command + if (!bdm_ready(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR; + // write the address (same address for second word) + if (!bdm_address(addr)) return TERM_ERR; + // write the second value + if (!bdm_put((uint32_t*)&value2, BDM_WORDSIZE)) return TERM_ERR; + // wait until MCU responds + return (bdm_ready(BDM_NOP)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Writes a word then reads back a result from the same address + The BDM commands are overlapped to make things a bit faster + A BDM_NOP command is then sent to end the sequence of overlapping commands + + @param result read result (out) + addr address + value value to write + + @return status flag +*/ + +uint8_t memwrite_word_read_word(uint16_t* result, const uint32_t* addr, const uint16_t value) { + + if (!IN_BDM) return TERM_ERR; + + // write command code + if (!bdm_command(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR; + // write the address + if (!bdm_address(addr)) return TERM_ERR; + // write the value + if (!bdm_put((uint32_t*)&value, BDM_WORDSIZE)) return TERM_ERR; + // wait until MCU responds and overlap the next read command + if (!bdm_ready(BDM_READ + BDM_WORDSIZE)) return TERM_ERR; + // write the address (same address for reading the result) + if (!bdm_address(addr)) return TERM_ERR; + // receive the response word + return (bdm_get((uint32_t*)result, BDM_WORDSIZE, BDM_NOP)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Gets a word from the MCU (follows a previously sent read or dump word cmd) + Sends a DUMP_WORD command so that dump commands overlap + + @param result read result (out) + + @return status flag +*/ +uint8_t memget_word(uint16_t* result) { + + if (!IN_BDM) return TERM_ERR; + // receive the response word + return (bdm_get((uint32_t*)result, BDM_WORDSIZE, BDM_DUMP + BDM_WORDSIZE)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Gets a long from the MCU (follows a previously sent read or dump long cmd) + Sends a DUMP_LONG command so that dump commands overlap + + @param result read result (out) + + @return status flag +*/ +uint8_t memget_long(uint32_t* result) { + + if (!IN_BDM) return TERM_ERR; + // receive the response words + return (bdm_get(result, BDM_LONGSIZE, BDM_DUMP + BDM_LONGSIZE)) ? TERM_OK : TERM_ERR; +} + +//----------------------------------------------------------------------------- +/** + Reads value from system register. + + @param result register value (out) + @param reg register + + @return status flag +*/ +uint8_t sysreg_read(uint32_t* result, uint8_t reg) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // read register + if (!bdm_read(result, BDM_RSREG + reg, NULL)) { + // clear the interface and fail + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Writes value to system register. + + @param reg register + @param value register value + + @return status flag +*/ +uint8_t sysreg_write(uint8_t reg, const uint32_t* value) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // write register + if (!bdm_write(NULL, BDM_WSREG + reg, value)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Reads value from A/D register. + + @param result register value (out) + @param reg register + + @return status flag +*/ +uint8_t adreg_read(uint32_t* result, uint8_t reg) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // read register + if (!bdm_read(result, BDM_RDREG + reg, NULL)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Writes value to A/D register. + + @param reg register + @param value register value + + @return status flag +*/ +uint8_t adreg_write(uint8_t reg, const uint32_t* value) { + // check state + if (!IN_BDM) { + return TERM_ERR; + } + + // write register + if (!bdm_write(NULL, BDM_WRREG + reg, value)) { + // clear the interface and fail + bdm_clear(); + return TERM_ERR; + } + + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + Issues a read command to MCU. + + @param result read result (out) + @param cmd command sequence + @param addr address (optional) + + @return succ / fail +*/ +bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr) { + *result = 0; + + // write command code + bdm_clk(cmd, CMD_BIT_COUNT); + if (bdm_response > BDM_CMDCMPLTE) { + return false; + } + + // write the optional address + if (addr) { + // first word + bdm_clk((uint16_t)(*addr >> 16), CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + // second word + bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + } + + // receive response words + uint8_t wait_cnt; + for (uint8_t curr_word = 0; curr_word < ((cmd & BDM_LONGSIZE) ? 2 : 1); + ++curr_word) { + // wait while MCU prepares the response + wait_cnt = ERR_COUNT; + do { + bdm_clk(BDM_NOP, CMD_BIT_COUNT); + } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0); + + // save the result + if (bdm_response < BDM_NOTREADY) { + (*result) <<= 16; + (*result) |= bdm_response; + } else { + // result was not received + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +/** + Issues a write command to MCU. + + @param num_words number of additional command words + @param cmd command sequence + + @return succ / fail +*/ +bool bdm_write(const uint32_t* addr, uint16_t cmd, const uint32_t* value) { + // write command code + bdm_clk(cmd, CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + + // write the optional address + if (addr) { + // first word + bdm_clk((uint16_t)((*addr) >> 16), CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + // second word + bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + } + + // write the value + if (cmd & BDM_LONGSIZE) { + bdm_clk((uint16_t)((*value) >> 16), CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + } + bdm_clk((uint16_t)(*value), CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + + // wait until MCU responds + uint8_t wait_cnt = ERR_COUNT; + do { + // read response + bdm_clk(BDM_NOP, CMD_BIT_COUNT); + } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0); + + // check if command succeeded + return (bdm_response == BDM_CMDCMPLTE); +} + +bool bdm_command (uint16_t cmd) { + // write command code + bdm_clk(cmd, CMD_BIT_COUNT); + return (bdm_response > BDM_NOTREADY) ? false : true; +} + +bool bdm_address (const uint32_t* addr) { + // write an address + // first word + bdm_clk((uint16_t)((*addr) >> 16), CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + // second word + bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT); + return (bdm_response > BDM_NOTREADY) ? false : true; +} + +bool bdm_get (uint32_t* result, uint8_t size, uint16_t next_cmd) { + // receive response words + *result = 0; + uint8_t wait_cnt; + for (uint8_t curr_word = 0; curr_word < ((size & BDM_LONGSIZE) ? 2 : 1); + ++curr_word) { + // wait while MCU prepares the response + wait_cnt = ERR_COUNT; + do { + bdm_clk(next_cmd, CMD_BIT_COUNT); + } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0); + + // save the result + if (bdm_response < BDM_NOTREADY) { + (*result) <<= 16; + (*result) |= bdm_response; + } else { + // result was not received + return false; + } + } + return true; +} + +bool bdm_put (const uint32_t* value, uint8_t size) { + // write the value + if (size & BDM_LONGSIZE) { + bdm_clk((uint16_t)((*value) >> 16), CMD_BIT_COUNT); + if (bdm_response > BDM_NOTREADY) { + return false; + } + } + bdm_clk((uint16_t)(*value), CMD_BIT_COUNT); + return (bdm_response > BDM_NOTREADY) ? false : true; +} + +bool bdm_ready (uint16_t next_cmd) { + // wait until MCU responds + uint8_t wait_cnt = ERR_COUNT; + do { + // read response + bdm_clk(next_cmd, CMD_BIT_COUNT); + } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0); + + // check if command succeeded + return (bdm_response == BDM_CMDCMPLTE); +} + +//----------------------------------------------------------------------------- +/** + Writes a word to target MCU via BDM line and gets the response. + + @param value value to write + @param num_bits value size, bits +*/ +void bdm_clk(uint16_t value, uint8_t num_bits) { +// PIN_BKPT.output(); +// PIN_DSI.output(); + LPC_GPIO2->FIODIR |= 0x00000004; + // clock the value via BDM + bdm_response = ((uint32_t)value) << (32 - num_bits); +// bool dsi; + + while (num_bits--) { + + // falling edge on BKPT/DSCLK + PIN_BKPT.write(0); + + // set DSI bit + PIN_DSI.write(bdm_response & 0x80000000); + bdm_response <<= 1; + + // read DSO bit + bdm_response |= PIN_DSO.read(); + + // short delay +// for (uint8_t c = 1; c; c--); +// wait_us(1); + + // rising edge on BKPT/DSCLK + PIN_BKPT.write(1); + + // short delay + for (uint8_t c = 1; c; c--); +// wait_us(1); + } + + PIN_DSI.input(); +// LPC_GPIO2->FIODIR &= 0xfffffffb; +} + +//----------------------------------------------------------------------------- +/** + Clears the BDM interface after errors. +*/ +void bdm_clear() { + bdm_clk (BDM_NOP, CMD_BIT_COUNT); + bdm_clk (BDM_NOP, CMD_BIT_COUNT); + bdm_clk (BDM_NOP, CMD_BIT_COUNT); + bdm_clk (BDM_NOP, CMD_BIT_COUNT); + + while (bdm_response > 0) { + bdm_clk(0, 1); + } + while (bdm_response < 1) { + bdm_clk(0, 1); + } + bdm_clk(0, 15); +} + +//----------------------------------------------------------------------------- +// EOF +//-----------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bdmcpu32.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,108 @@ +/******************************************************************************* + +bdmcpu32.h +(c) 2010 by Sophie Dexter + +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. + +*******************************************************************************/ + +#ifndef __BDMCPU32_H__ +#define __BDMCPU32_H__ + +#include "mbed.h" + +#include "common.h" +#include "bdmtrionic.h" +//#include "BDM.h" + + +// MCU status macros +#ifndef IGNORE_VCC_PIN + #define IS_CONNECTED (PIN_PWR) +#else + #define IS_CONNECTED true +#endif // IGNORE_VCC_PIN + +#define IN_BDM (PIN_FREEZE) +#define IS_RUNNING (PIN_RESET && !IN_BDM) + +// MCU management +uint8_t stop_chip(); +uint8_t reset_chip(); +uint8_t run_chip(const uint32_t* addr); +uint8_t restart_chip(); +uint8_t step_chip(); +uint8_t bkpt_low(); +uint8_t bkpt_high(); +uint8_t reset_low(); +uint8_t reset_high(); + +// memory +uint8_t memread_byte(uint8_t* result, const uint32_t* addr); +uint8_t memread_word(uint16_t* result, const uint32_t* addr); +uint8_t memread_long(uint32_t* result, const uint32_t* addr); +uint8_t memdump_byte(uint8_t* result); +uint8_t memdump_word(uint16_t* result); +uint8_t memdump_long(uint32_t* result); +uint8_t memwrite_byte(const uint32_t* addr, uint8_t value); +uint8_t memwrite_word(const uint32_t* addr, uint16_t value); +uint8_t memwrite_long(const uint32_t* addr, const uint32_t* value); +uint8_t memfill_byte(uint8_t value); +uint8_t memfill_word(uint16_t value); +uint8_t memfill_long(const uint32_t* value); + +// memory split commands +// Setup a start of a sequence of BDM operations +// read commands +uint8_t memread_byte_cmd(const uint32_t* addr); +uint8_t memread_word_cmd(const uint32_t* addr); +uint8_t memread_long_cmd(const uint32_t* addr); +// write commands +uint8_t memwrite_byte_cmd(const uint32_t* addr); +uint8_t memwrite_word_cmd(const uint32_t* addr); +uint8_t memwrite_long_cmd(const uint32_t* addr); +// follow on commands +// dump bytes/words/longs +uint8_t memget_word(uint16_t* result); +uint8_t memget_long(uint32_t* result); +// read and write bytes +uint8_t memwrite_write_byte(const uint32_t* addr, const uint8_t value); +uint8_t memwrite_read_byte(const uint32_t* addr, const uint8_t value); +uint8_t memwrite_nop_byte(const uint32_t* addr, const uint8_t value); +uint8_t memread_read_byte(uint8_t* result, const uint32_t* addr); +uint8_t memread_write_byte(uint8_t* result, const uint32_t* addr); +uint8_t memread_nop_byte(uint8_t* result, const uint32_t* addr); +// +uint8_t memwrite_word_write_word(const uint32_t* addr, const uint16_t value1, const uint16_t value2); +uint8_t memwrite_word_read_word(uint16_t* result, const uint32_t* addr, const uint16_t value); + + +// registers +uint8_t sysreg_read(uint32_t* result, uint8_t reg); +uint8_t sysreg_write(uint8_t reg, const uint32_t* value); +uint8_t adreg_read(uint32_t* result, uint8_t reg); +uint8_t adreg_write(uint8_t reg, const uint32_t* value); + +// bdm part commands +bool bdm_command (uint16_t cmd); +bool bdm_address (const uint32_t* addr); +bool bdm_get (uint32_t* result, uint8_t size, uint16_t next_cmd); +bool bdm_put (const uint32_t* value, uint8_t size); +bool bdm_ready (uint16_t next_cmd); + +#endif // __BDMCPU32_H__ +//----------------------------------------------------------------------------- +// EOF +//----------------------------------------------------------------------------- \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bdmtrionic.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,894 @@ +/******************************************************************************* + +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); + + // add the terminating character + if (curr_addr < *end_addr - 4) { + pc.putc(TERM_OK); + // light up the activity LED + // led_on(LED_ACT); + led3 = 1; + } + + 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 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(); + + 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 + led3 = 1; + 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; + } + } + // 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 +// led_on(LED_ACT); + led3 = 1; + } + + // 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 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 + 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; + } + + timer.reset(); + timer.start(); + + uint32_t curr_addr = 0; + + switch (type) { + // AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7) + case AMD29F400B: + case AMD29F400T: + case AMD29F010: + printf("Erasing 29F400/010 type FLASH chips...\r\n"); + if (erase_am29() == TERM_ERR) { + 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) == TERM_ERR) { + 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 "Starange!" + 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 + 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 + led3 = 1; + + } + + timer.stop(); + fclose(fp); + + if (curr_addr == flash_size) { + printf("Programming took %#.1f seconds.\r\n",timer.read()); + 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; + } + + // 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; + + uint8_t err_cnt = ERR_COUNT; + while (--err_cnt) { + // typical erase time = 1s + // Allow up to 25.5 seconds erase time + wait_ms(100); + if (memread_word(&verify_value, &addr) == TERM_OK && verify_value == 0xffff) { + // erase completed normally + reset_am29(); + return true; + } + } + + // 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); + 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(&start_addr, 0xffff) == TERM_OK && + memwrite_word(&start_addr, 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; + + 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 +// led3 = (addr & 0x400); + led3 = 1; + } + + // erase flash + addr = *start_addr; + uint8_t verify_value; + + + 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 + led3 = 1; + } + } + // 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 +// wait_us(10); + // 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) { + + // 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) + long_value = 0x00fffa04; + if (memwrite_word(&long_value, 0x7f00) != TERM_OK) return TERM_ERR; + + // Disable watchdog and monitors + long_value = 0x00fffa21; + if (memwrite_byte(&long_value, 0x00) != TERM_OK) return TERM_ERR; + + // Chip select pin assignments + long_value = 0x00fffa44; + if (memwrite_word(&long_value, 0x3fff) != TERM_OK) return TERM_ERR; + + // Boot Chip select read only, one wait state + 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 + 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 + long_value = 0x00fffc14; + if (memwrite_word(&long_value, 0x0040) != TERM_OK) return TERM_ERR; + + // PQS Data Direction output + 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 +// long_value = 0x00fffb04; +// if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR; + return TERM_OK; +} + +//----------------------------------------------------------------------------- +/** + 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) { + if (memwrite_word(&am29_id[i].addr, am29_id[i].val) != TERM_OK) return false; + } + if (memread_long(&value, &addr) != TERM_OK) return false; + *make = (uint8_t)(value >> 24); + *type = (uint8_t)(value >> 8); + printf("FLASH id bytes: %08x, make: %02x, type: %02x\r\n", value, *make, *type); + switch (*type) { + case AMD29F400B: + case AMD29F400T: + case AMD29F010: + case AMD28F010: + case INTEL28F010: + case AMD28F512: + case INTEL28F512: + ret = true; + default: + ret = false; + } + return ret; +} + +//----------------------------------------------------------------------------- +// EOF +//-----------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bdmtrionic.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,45 @@ +/******************************************************************************* + +bdmtrionic.cpp +(c) 2010 by Sophie Dexter + +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. + +*******************************************************************************/ + +#ifndef __BDMTRIONIC_H__ +#define __BDMTRIONIC_H__ + +#include "mbed.h" + +#include "common.h" +#include "bdmcpu32.h" + +// global variables +static bool verify_flash = 1; + +// public functions +uint8_t dump_flash(const uint32_t* start_addr, const uint32_t* end_addr); +uint8_t erase_flash(const char* flash_type, const uint32_t* start_addr, + const uint32_t* end_addr); +uint8_t write_flash(const char* flash_type, const uint32_t* start_addr); + +uint8_t prep_t5_do(void); +uint8_t dump_trionic(void); +uint8_t flash_trionic(void); + +#endif +//----------------------------------------------------------------------------- +// EOF +//-----------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/can232.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,205 @@ +/******************************************************************************* + +can232.cpp +(c) 2010 by Sophie Dexter +portions (c) 2009, 2010 by Janis Silins (johnc) + +Lawicel CAN232 type functions for Just4Trionic by Just4pLeisure + +******************************************************************************** + +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 "can232.h" + +// constants +#define CMD_BUF_LENGTH 32 ///< command buffer size + +// command characters + +#define CMD_CLOSE 'C' ///< Close the CAN device +#define CMD_OPEN 'O' ///< Open the CAN device (do this before an S/s command) + +#define CMD_PRESET_SPEED 'S' ///< Sn: set preconfigured speeds +#define CMD_SPEED_0 '0' ///< 10 kbits +#define CMD_SPEED_1 '1' ///< 20 kbits +#define CMD_SPEED_2 '2' ///< 50 kbits +#define CMD_SPEED_3 '3' ///< 100 kbits +#define CMD_SPEED_4 '4' ///< 125 kbits +#define CMD_SPEED_5 '5' ///< 250 kbits +#define CMD_SPEED_6 '6' ///< 500 kbits +#define CMD_SPEED_7 '7' ///< 800 kbits +#define CMD_SPEED_8 '8' ///< 1 mbits +#define CMD_DIRECT_SPEED 's' ///< sxxyy: set the CAN bus speed registers directly +///< xx: BTR0 register setting +///< yy: BTR1 register setting + +#define CMD_SEND_11BIT 't' ///< tiiildd..: send 11 bit id CAN frame +///< iii: identfier 0x0..0x7ff +///< l: Number of data bytes in CAN frame 0..8 +///< dd..: data byte values 0x0..0xff (l pairs) +#define CMD_SEND_29BIT 'T' ///< Tiiiiiiiildd..: send 29 bit id CAN frame +///< iiiiiiii: identifier 0x0..0x1fffffff +///< l: Number of data bytes in CAN frame 0..8 +///< dd..: data byte values 0x0..0xff (l pairs) + + +#define CMD_READ_FLAGS 'F' ///< Read flags !?! + +#define CMD_ACCEPT_CODE 'M' ///< Mxxxxxxxx: Acceptance code e.g. 0x00000000 } accept +#define CMD_ACCEPT_MASK 'm' ///< mxxxxxxxx: Acceptance mask e.g. 0xffffffff } all + +#define CMD_VERSION 'V' ///< Replies with Firmware and hardware version numbers; 2 bytes each +#define CMD_SERIAL_NUMBER 'N' ///< Replies with serial number; 4 bytes + +#define CMD_TIMESTAMP 'Z' ///< Zn: n=0 means timestamp off, n=1 means timestamp is on +///< Replies a value in milliseconds with two bytes 0x0..0xfa5f +///< equivalent to 0..60 seconds + + + +// static variables +static char cmd_buffer[CMD_BUF_LENGTH]; ///< command string buffer +static uint32_t can_id; ///< can message id +static uint32_t can_len; ///< can message length +static uint8_t can_msg[8]; ///< can message frame - up to 8 bytes + +// private functions +uint8_t execute_can_cmd(); + +// command argument macros +#define CHECK_ARGLENGTH(len) \ + if (cmd_length != len + 2) \ + return TERM_ERR + +#define GET_NUMBER(target, offset, len) \ + if (!ascii2int(target, cmd_buffer + 2 + offset, len)) \ + return TERM_ERR + + + +void can232() { + + // main loop + *cmd_buffer = '\0'; + char ret; + char rx_char; + can_open(); + can.attach(&show_can_message); +// bool (*reset_func)(); + while (true) { + // read chars from USB +// Trionic5ShowCANMessage(); + if (pc.readable()) { + rx_char = pc.getc(); + switch (rx_char) { + // 'ESC' key to go back to mbed Just4Trionic 'home' menu + case '\e': + can_close(); + can.attach(NULL); + return; + // end-of-command reached + case TERM_OK : + // execute command and return flag via USB + ret = execute_can_cmd(); + pc.putc(ret); + // reset command buffer + *cmd_buffer = '\0'; + // light up LED +// ret == TERM_OK ? led_on(LED_ACT) : led_on(LED_ERR); + ret == TERM_OK ? led3 = 1 : led4 = 1; + break; + // another command char + default: + // store in buffer if space permits + if (StrLen(cmd_buffer) < CMD_BUF_LENGTH - 1) { + StrAddc(cmd_buffer, rx_char); + } + break; + } + } + } +} + +//----------------------------------------------------------------------------- +/** + Executes a command and returns result flag (does not transmit the flag + itself). + + @return command flag (success / failure) +*/ + +uint8_t execute_can_cmd() { + uint8_t cmd_length = strlen(cmd_buffer); + char cmd = *(cmd_buffer + 1); + + // command groups + switch (*cmd_buffer) { + // adapter commands + case CMD_SEND_11BIT: + if (cmd_length < 7) return TERM_ERR; + GET_NUMBER(&can_id, -1, 3); + GET_NUMBER(&can_len, 2, 1); + if (cmd_length < (4 + (can_len * 2))) return TERM_ERR; + for (uint8_t i = 0; i < (uint8_t)can_len; i++) { + uint32_t result; + GET_NUMBER(&result, (3 + (i * 2)), 2); + can_msg[i] = (uint8_t)result; + } + return (can_send_timeout (can_id, (char*)can_msg, (uint8_t)can_len, 500)) ? TERM_OK : TERM_ERR; + + case CMD_SEND_29BIT: + break; + + case CMD_CLOSE: + can_close(); + return TERM_OK; + case CMD_OPEN: + can_open(); + return TERM_OK; + + case CMD_PRESET_SPEED: + CHECK_ARGLENGTH(0); + switch (cmd) { + // get firmware version + case CMD_SPEED_0: + return (can.frequency(10000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_1: + return (can.frequency(20000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_2: + return (can.frequency(50000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_3: + return (can.frequency(100000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_4: + return (can.frequency(125000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_5: + return (can.frequency(250000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_6: + return (can.frequency(500000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_7: + return (can.frequency(800000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_8: + return (can.frequency(1000000)) ? TERM_OK : TERM_ERR; + } + break; + + case CMD_DIRECT_SPEED: + CHECK_ARGLENGTH(0); + switch (cmd) { + case CMD_SPEED_0: + return (can.frequency(47619)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_1: + return (can.frequency(500000)) ? TERM_OK : TERM_ERR; + case CMD_SPEED_2: + return (can.frequency(615000)) ? TERM_OK : TERM_ERR; + } + break; + } + + // unknown command + return TERM_ERR; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/can232.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,25 @@ +/******************************************************************************* + +can232.h +(c) 2010 by Sophie Dexter +portions (c) 2009, 2010 by Janis Silins (johnc) + +******************************************************************************** + +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. + +*******************************************************************************/ + +#ifndef __CAN232_H__ +#define __CAN232_H__ + +#include "mbed.h" + +#include "common.h" +#include "canutils.h" + +extern void can232(); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/canutils.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,117 @@ +/******************************************************************************* + +canutils.cpp +(c) 2010 by Sophie Dexter + +General purpose CAN bus functions for Just4Trionic by Just4pLeisure +Functions that work with the CAN bus directly. Anything to do with the CAN bus +must (should anyway) be done by one of these functions. + +******************************************************************************** + +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 "canutils.h" + +//CAN can2(p30, p29); +// Use a timer to see if things take too long +Timer CANTimer; + + +void can_open() { + // activate external can transceiver + can.reset(); + can_rs_pin = 0; +} + +void can_close() { + // disable external can transceiver + can_rs_pin = 1; + can.reset(); +} + +uint8_t can_set_speed(uint32_t speed) { + // 600kbit/s first - basically sets up CAN interface, but to wrong speed - not sure what else it does +// can.frequency(600000); + // 615kbit/s direct write of 615 kbit/s speed setting +// LPC_CAN2->BTR = 0x370002; + return (can.frequency(speed)) ? TERM_OK : TERM_ERR; +} + + +void show_can_message() { + CANMessage can_MsgRx; + if (can.read(can_MsgRx)) { + printf("w%03x%d", can_MsgRx.id, can_MsgRx.len); + for (char i=0; i<can_MsgRx.len; i++) { + printf("%02x", can_MsgRx.data[i]); + } + printf("\r\n"); + } +} + +// +// Sends a CAN Message, returns FALSE if the message wasn't sent in time +// +// inputs: integer CAN message 'id', pointer to 'frame', integer message length and integer timeout +// return: TRUE if the CAN message was sent before the 'timeout' expires +// FALSE if 'timeout' expires or the message length is wrong +// +extern bool can_send_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout) { + CANTimer.reset(); + CANTimer.start(); + while (CANTimer.read_ms() < timeout) { + if (can.write(CANMessage(id, frame, len))) { + CANTimer.stop(); + led1 = 1; + return TRUE; + } + } + can.reset(); + CANTimer.stop(); + return FALSE; +} + +// +// Waits for a CAN Message with the specified 'id' for a time specified by the 'timeout' +// All other messages are ignored +// The CAN message frame is returned using the pointer to 'frame' +// +// inputs: integer CAN message 'id', pointer to 'frame' for returning the data +// integer expected length of message, len and integer for the waiting time 'timeout' +// +// return: TRUE if a qualifying message was received +// FALSE if 'timeout' expires or the message length is wrong +// +extern bool can_wait_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout) { + CANMessage CANMsgRx; + CANTimer.reset(); + CANTimer.start(); + while (CANTimer.read_ms() < timeout) { + if (can.read(CANMsgRx)) { +/* + printf("w%03x8", CANMsgRx.id); + for (char i=0; i<len; i++) { + printf("%02x", CANMsgRx.data[i]); + } + printf("\n\r"); +// */ + led2 = 1; + if (CANMsgRx.id == id) { + CANTimer.stop(); +// if (T5MsgRx.len != len) +// return FALSE; + for (int i=0; i<len; i++) + frame[i] = CANMsgRx.data[i]; + return TRUE; + } + } + } + can.reset(); + CANTimer.stop(); + return FALSE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/canutils.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,30 @@ +/******************************************************************************* + +canutils.h - information and definitions needed for the CAN bus +(c) 2010 by Sophie Dexter + +******************************************************************************** + +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. + +*******************************************************************************/ + +#ifndef __CANUTILS_H__ +#define __CANUTILS_H__ + +#include "CAN.h" +#include "mbed.h" + +#include "common.h" + +extern void can_open(); +extern void can_close(); +extern uint8_t can_set_speed(uint32_t speed); +extern void show_can_message(); + +extern bool can_send_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout); +extern bool can_wait_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,102 @@ +/******************************************************************************* + +common.h - information and definitions needed by parts of Just4Trionic +(c) by 2010 Sophie Dexter +portions (c) 2009, 2010 by Janis Silins (johnc) + +******************************************************************************** + +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. + +*******************************************************************************/ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +//#include <stdint.h> +//#include <stdbool.h> + +#include "mbed.h" + +#include "sizedefs.h" +#include "strings.h" +#include "interfaces.h" + +// build configuration +//#define IGNORE_VCC_PIN ///< uncomment to ignore the VCC pin + +// constants +#define FW_VERSION_MAJOR 0x1 ///< firmware version +#define FW_VERSION_MINOR 0x1 + +#define CR 0x0D +#define NL 0x0A +#define BELL 0x07 + +#define TRUE 1 +#define FALSE 0 + + +// bit macros +#define SETBIT(x,y) (x |= (y)) ///< set bit y in byte x +#define CLEARBIT(x,y) (x &= (~(y))) ///< clear bit y in byte x +#define CHECKBIT(x,y) (((x) & (y)) == (y)) ///< check bit y in byte x + +// command return flags and character constants +#define TERM_OK 13 ///< command terminator or success flag +#define TERM_ERR 7 ///< error flag +#define TERM_BREAK 0x1b ///< command break flag + +#define ERR_COUNT 255 ///< maximum error cycles + +#define FILE_BUF_LENGTH 0x1000 ///< file buffer size +static char file_buffer[FILE_BUF_LENGTH]; ///< file buffer + +// FLASH chip manufacturer id values +#define AMD 0x01 +#define CSI 0x31 +#define INTEL 0x89 + +// FLASH chip type values +#define INTEL28F512 0xB8 +#define AMD28F512 0x25 +#define INTEL28F010 0xB4 +#define AMD28F010 0xA7 +#define AMD29F010 0x20 +#define AMD29F400T 0x23 +#define AMD29F400B 0xAB +//#define 29F400T 0x2223 +//#define 29F400B 0x22AB + +// TRIONIC ECU Start addresses +#define T52FLASHSTART 0x60000 +#define T55FLASHSTART 0x40000 +#define T7FLASHSTART 0x00000 + +// TRIONIC ECU FLASH sizes +#define T52FLASHSIZE 0x20000 +#define T55FLASHSIZE 0x40000 +#define T7FLASHSIZE 0x80000 + +// TRIONIC ECU Last address +#define TRIONICLASTADDR 0x7FFFF + +// TRIONIC ECU RAM sizes +#define T5RAMSIZE 0x8000 +#define T7RAMSIZE 0x8000 + +// Initial Stack pointer values used by Trionic (1st 4 bytes of BIN file) +#define T5POINTER 0xFFFFF7FC +#define T7POINTER 0xFFFFEFFC + +// public functions +void led_on(uint8_t led); +bool ascii2int(uint32_t* val, const char* str, uint8_t length); + +#endif // __COMMON_H__ + +//----------------------------------------------------------------------------- +// EOF +//-----------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interfaces.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,60 @@ +/******************************************************************************* + +interfaces.cpp +(c) 2010 by Sophie Dexter + +******************************************************************************** + +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 "interfaces.h" + +//Serial pc(USBTX, USBRX); // tx, rx +Serial pc(USBTX, USBRX); + +// A timer for timing how long things take to happen +Timer timer; + +// We use CAN on mbed pins 29(CAN_TXD) and 30(CAN_RXD). +CAN can(p30, p29); +// CAN_RS pin at Philips PCA82C250 can bus controller. +// activate transceiver by pulling this pin to GND. +// (Rise and fall slope controlled by resistor R_s) +// (+5V result in tranceiver standby mode) +// For further information see datasheet page 4 +DigitalOut can_rs_pin(p28); + +// Need to create this to be able to read and write files on the mbed 'disk' +LocalFileSystem local("local"); + + +DigitalIn PIN_PWR(p19); // power supply +DigitalIn PIN_NC(p20); // connection signal +DigitalInOut PIN_BERR(p21); // double bus fault input - will be an input when it is working properly +DigitalInOut PIN_BKPT(p22); // breakpoint/serial clock +DigitalInOut PIN_RESET(p23); // reset signal +DigitalInOut PIN_DSI(p24); // data input (to ECU) signal +DigitalIn PIN_DS(p25); // data strobe signal (not used) +DigitalIn PIN_FREEZE(p26); // freeze signal +DigitalIn PIN_DSO(p27); // data output (from ECU) signal + +//LEDS + +// Use the LEDs to if anything is happening + +DigitalOut led1(LED1); // LED1 CAN send +DigitalOut led2(LED2); // LED2 CAN receive +DigitalOut led3(LED3); // BDM activity LED +DigitalOut led4(LED4); // Error LED + +Ticker ticker; + +void leds_off() { + led1 = 0; + led2 = 0; + led3 = 0; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interfaces.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,50 @@ +/******************************************************************************* + +interfaces.cpp - information and definitions about Just4Trionic external interfaces +(c) 2010 by Sophie Dexter + +******************************************************************************** + +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. + +*******************************************************************************/ + +#ifndef __INTERFACES_H__ +#define __INTERFACES_H__ + +#include "mbed.h" + +extern Serial pc; //Serial pc(USBTX, USBRX); // tx, rx + +extern CAN can; //Serial pc(USBTX, USBRX); // tx, rx +extern DigitalOut can_rs_pin; // + +extern LocalFileSystem local; //Serial pc(USBTX, USBRX); // tx, rx + +extern Timer timer; + +extern DigitalIn PIN_PWR; // power supply +extern DigitalIn PIN_NC; // connection signal +extern DigitalInOut PIN_BERR; // double bus fault input - will be an input when it is working properly +extern DigitalInOut PIN_BKPT; // breakpoint/serial clock +extern DigitalInOut PIN_RESET; // reset signal +extern DigitalInOut PIN_DSI; // data input (to ECU) signal +extern DigitalIn PIN_DS; // data strobe signal (not used) +extern DigitalIn PIN_FREEZE; // freeze signal +extern DigitalIn PIN_DSO; // data output (from ECU) signal + +//LEDS + +// Use the LEDs to see if anything is happening +extern DigitalOut led1; // LED1 CAN send +extern DigitalOut led2; // LED2 CAN receive +extern DigitalOut led3; // BDM activity LE +extern DigitalOut led4; // Error LED + +extern Ticker ticker; + +void leds_off(void); + +#endif // __INTERFACES_H__ \ No newline at end of file
--- a/main.cpp Wed May 19 12:39:18 2010 +0000 +++ b/main.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -1,7 +1,8 @@ /******************************************************************************* -Just4Trionic by Just4pLeisure +Just4Trionic by Just4pLeisure ***************************** +(c) 2010 by Sophie Dexter Whilst I have written this program myself I could not have done it without a lot of help and the original ideas and programs written by: @@ -12,7 +13,10 @@ Tomi Liljemark - Lots of information and programs about the Saab CAN bus http://pikkupossu.1g.fi/tomi/projects/projects.html. Scott Howard - Author of the BDM software. -Plus inspiration and ideas from many others, including johnc. +Janis Silins - Valued contributor at http://www.ecuproject.com and creator of +USBBDM. For sharing his BDM software (which also had a very useful method of +entering commands) +Plus inspiration and ideas from many others... Sophie x @@ -24,7 +28,33 @@ ******************************************************************************** -Version 1 (04/2010)- The basic functions are working, but not very easy to use +Version 1.1 (09/2010) - Still very crude way of doing things + +Additions since Version 1: + The BDM interface is now working + Based on Janis Silin's BDM software with modifications and additions + Detect which type of FLASH chip is fitted to work out type of ECU + Modifications to FLASH algorithms - I think my algorithms are + closer to the datasheet methods. Still to do: + Separate pulse counters for 28Fxxx erase + DQ7 and DQ5 checking method for 29Fxxx FLASH + Works for T5.5 ECUs with 28F010 and 29F010 chips + Probably works with T5.2 ECUs (chip detection method) + MAY work with T7 ECUs ('prep' method may need changes - I can't test T7) + NOTE: Some of Janis' original BDM commands may not work, or at least + not as originally intended + Lawicell CAN232 interface partially working + Only a few Lawicell message types to open/close, set speed and write + Trionic5 CAN functions + All-in-one 'D' and 'F' commands to DUMP and FLASH BIN files + Lots of checking for errors, either works or says it failed + No need to interpret the cryptic CAN messages anymore + Should now work for T5.2 and T5.5 ECUs + Detects FLASH chip type and works out which ECU is connected T5.2/5.5 + +******************************************************************************** + +Version 1 (04/2010)- The basic CAN functions are working I have decided to 'release' this software somewhat prematurely because the FLASH chips in my spare ECU have 'died' and I don't know when I will be able to do @@ -51,63 +81,126 @@ *******************************************************************************/ #include "mbed.h" - -#include "strings.h" -#include "BDM.h" -#include "CAN232.h" -#include "Trionic5.h" - -Serial pc(USBTX, USBRX); // tx, rx +// +#include "common.h" +#include "bdm.h" +#include "can232.h" +#include "t5can.h" -#define CR 0x0D -#define NL 0x0A -#define BELL 0x07 +// constants +#define CMD_BUF_LENGTH 32 ///< command buffer size -#define TRUE 1 -#define FALSE 0 +// static variables +static char cmd_buffer[CMD_BUF_LENGTH]; ///< command string buffer -void ShowHelp(); +// private functions +uint8_t execute_just4trionic_cmd(); +void show_just4trionic_help(); int main() { // fast serial speed // pc.baud(921600); pc.baud(115200); - // make plenty of space for command from RS232 - char command[5]; - ShowHelp(); - while (1) { -// Only get 2 characters, the command and \r -// For now I cannot work out how to use gets() so only single characters -// can be used for commands :-( -// -// At the moment only option '5' does anything - the Trionic5 functions -// - pc.gets(command,2); - int len = strlen(command); - if (len != 1) - printf ("\a"); - else if (ToUpper(command[0]) == 'B') - BDM(); - else if (ToUpper(command[0]) == 'O') - CAN232(); - else if (ToUpper(command[0]) == '5') - Trionic5(); - else if (ToUpper(command[0]) == 'H') - ShowHelp(); -// Unrecognised so ring the BELL :( - else - printf ("\a"); + + // the address of the function to be attached (leds_off) and the interval (0.1 seconds) + // This 'ticker' turns off the activity LEDs so that they don't stay on if something has gone wrong + ticker.attach(&leds_off, 0.1); + + // clear incoming buffer + // sometimes TeraTerm gets 'confused'. johnc does this in his code + // hopefully this will fix the problem + // unfortunately it doesn't, but it seems like a good idea + char rx_char; + while (pc.readable()) + rx_char = pc.getc(); + + show_just4trionic_help(); + + // main loop + *cmd_buffer = '\0'; + char ret; + while (true) { + // read chars from USB + // send received messages to the pc over USB connection + // This function displays any CAN messages that are 'missed' by the other functions + // Can messages might be 'missed' because they are received after a 'timeout' period + // or because they weren't expected, e.g. if the T5 ECU resets for some reason + t5_can_show_can_message(); + if (pc.readable()) { + // turn Error LED off for next command + led4 = 0; + rx_char = pc.getc(); + switch (rx_char) { + // end-of-command reached + case TERM_OK : + // execute command and return flag via USB + timer.reset(); + timer.start(); + ret = execute_just4trionic_cmd(); + show_just4trionic_help(); + pc.putc(ret); + // reset command buffer + *cmd_buffer = '\0'; + // light up LED +// ret == TERM_OK ? led_on(LED_ACT) : led_on(LED_ERR); + ret == TERM_OK ? led3 = 1 : led4 = 1; + break; + // another command char + default: + // store in buffer if space permits + if (StrLen(cmd_buffer) < CMD_BUF_LENGTH - 1) { + StrAddc(cmd_buffer, rx_char); + } + break; + } + } } } -void ShowHelp() { +//----------------------------------------------------------------------------- +/** + Executes a command and returns result flag (does not transmit the flag + itself). + + @return command flag (success / failure) +*/ +uint8_t execute_just4trionic_cmd() { + + +// uint8_t cmd_length = strlen(cmd_buffer); + // command groups + switch (*cmd_buffer) { +// CHECK_ARGLENGTH(0); + case 'b': + case 'B': + bdm(); + return TERM_OK; + case 'o': + case 'O': + can232(); + return TERM_OK; + case '5': + t5_can(); + return TERM_OK; + case 'h': + case 'H': + return TERM_OK; + default: + break; + } + +// unknown command + return TERM_ERR; +} + +void show_just4trionic_help() { printf("Just4Trionic Command Menu\r\n"); printf("=========================\r\n"); - printf("b/B - Start BDM interface (NOT DONE)\r\n"); - printf("o/O - Open Lawicel CAN232 type interface (NOT DONE)\r\n"); + printf("b/B - Start BDM interface\r\n"); + printf("o/O - Open Lawicel CAN232 type interface\r\n"); printf("5 - Start Trionic5 ECU CAN interface\r\n"); printf("\r\n"); printf("h/H - show this help menu\r\n"); + printf("\r\n"); return; -} - +} \ No newline at end of file
--- a/mbed.bld Wed May 19 12:39:18 2010 +0000 +++ b/mbed.bld Tue Sep 14 21:02:04 2010 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0 +http://mbed.org/users/mbed_official/code/mbed/builds/9114680c05da
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sizedefs.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,42 @@ +/******************************************************************************* + +sizedefs.h - definitions of types used in Just4Trionic by Just4pLeisure +(c) 2010 by Sophie Dexter +portions (c) 2009, 2010 by Janis Silins (johnc) + +A derivative work based on: + * sizedefs.h - define parameter types for BDM package + * Copyright (C) 1992 by Scott Howard, all rights reserved + * Permission is hereby granted to freely copy and use this code or derivations thereof + * as long as no charge is made to anyone for its use + * + * this file defines the types BYTE, WORD, and LONG to declare types + * that match the data sizes used in the target microcontroller(s) + * BYTE is one byte, WORD is two bytes, LONG is 4 bytes + * these are all unsigned quantities + * change these definitions if you are using a compiler with different default sizes + */ + +/******************************************************************************* + +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. + +*******************************************************************************/ + +#ifndef __SIZEDEFS_H__ +#define __SIZEDEFS_H__ + +#define BYTE unsigned char +// For MBED / ARM Cortex3 use 'unsigned short' for WORD (2 bytes) +#define WORD unsigned short +#define LONG unsigned long + +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned long + +#endif + +/* end of sizedefs.h */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srecutils.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,54 @@ +/******************************************************************************* + +srecutils.h +(c) 2010 by Sophie Dexter + +Functions for manipulating Motorala S-records + +******************************************************************************** + +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 "srecutils.h" + +// SRecGetByte +// +// Returns an int which is a single byte made up from two ascii characters read from an S-record file +// +// inputs: a file pointer for the S-record file +// return: an integer which is the byte in hex format + +int SRecGetByte(FILE *fp) { + int c = 0; + int retbyte = 0; + + for(int i=0; i<2; i++) { + if ((c = fgetc(fp)) == EOF) return -1; + c -= (c > '9') ? ('A' - 10) : '0'; + retbyte = (retbyte << 4) + c; + } + return retbyte; +} + +// SRecGetAddress +// +// Returns an int which is the address part of the S-record line +// The S-record type 1/2/3 or 9/8/7 determines if there are 2, 3 or 4 bytes in the address +// +// inputs: an integer which is the number of bytes that make up the address; 2, 3 or 4 bytes +// a file pointer for the S-record file +// return: an integer which is the load address for the S-record + +int SRecGetAddress(int size, FILE *fp) { + int address = 0; + for (int i = 0; i<size; i++) + { + address <<= 8; + address |= SRecGetByte (fp); + } + return address; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srecutils.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,19 @@ +/******************************************************************************* + +srecutils.h - information and definitions needed for working with S-Records +(c) 2010 by Sophie Dexter + +******************************************************************************** + +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 "mbed.h" + +#include "common.h" + +extern int SRecGetByte(FILE *fp); +extern int SRecGetAddress(int size, FILE *fp);
--- a/strings.cpp Wed May 19 12:39:18 2010 +0000 +++ b/strings.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -1,6 +1,7 @@ /******************************************************************************* -Strings.cpp - By Sophie Dexter, April 2010 +strings.cpp +(c) 2010 by Sophie Dexter This C++ module provides functions for working with 'strings' of ascii 'char's @@ -15,6 +16,7 @@ accept liability for any damage arising from its use. *******************************************************************************/ + #include "strings.h" // copies a string, s2, (array of chars) to another string, s1. @@ -81,4 +83,81 @@ s++; } return s; -} \ No newline at end of file +} + +// StrAddc adds a single char to the end of a string + +char *StrAddc (char *s, const char c) { + char *s1 = s; + +// Find the end of the string 's' + while (*s) + *s++; +// add the new character + *s++ = c; +// put the end of string character at its new position + *s = '\0'; + return s1; +} + +//----------------------------------------------------------------------------- +/** + Converts an ASCII character to low nibble of a byte. + + @param rx_byte character to convert + + @return resulting value +*/ +uint8_t ascii2nibble(char str) +{ + return str >= 'a' ? (str - 'a' + 10) & 0x0f : + (str >= 'A' ? (str - 'A' + 10) & 0x0f : + (str - '0') & 0x0f); +} + +//----------------------------------------------------------------------------- +/** + Converts an ASCII string to integer (checks string contents beforehand). + + @param val destination integer + @param str pointer to source string + @param length length of source string + + @return succ / fail +*/ +bool ascii2int(uint32_t* val, const char* str, uint8_t length) +{ + // nothing to convert + if (!str || length < 1) + { + *val = 0; + return false; + } + + // check string contents + uint8_t shift; + for (shift = 0; shift < length; ++shift) + { + if (!isxdigit(*(str + shift))) + { + // not a hex value + *val = 0; + return false; + } + } + + // convert string + *val = ascii2nibble(*(str++)); + for (shift = 1; shift < length; ++shift) + { + *val <<= 4; + *val += ascii2nibble(*(str++)); + } + return true; +} + +int isxdigit ( int ch ) +{ + return (unsigned int)( ch - '0') < 10u || + (unsigned int)((ch | 0x20) - 'a') < 6u; +}
--- a/strings.h Wed May 19 12:39:18 2010 +0000 +++ b/strings.h Tue Sep 14 21:02:04 2010 +0000 @@ -1,12 +1,27 @@ +/******************************************************************************* -// strings.h - information and definitions needed for working with strings of characters (ascii 'char') +strings.h - information and definitions needed for working with strings of +characters (ascii 'char') +(c) 2010 by Sophie Dexter + +******************************************************************************** -#define TRUE 1 -#define FALSE 0 +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 "common.h" +#include "sizedefs.h" extern char *StrCpy(char *s1, char *s2); extern int StrLen(char *s); extern bool StrCmp(char *s1, char *s2); extern char ToUpper(char c); extern char ToLower(char c); -extern char *aToh(char *s); \ No newline at end of file +extern char *aToh(char *s); +extern char *StrAddc (char *s, const char c); +extern uint8_t ascii2nibble(char str); +extern bool ascii2int(uint32_t* val, const char* str, uint8_t length); +extern int isxdigit ( int ch );
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/t5can.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,1020 @@ +/******************************************************************************* + +trionic5.cpp - CAN Bus functions for Just4Trionic by Just4pLeisure +(c) 2010 by Sophie Dexter + +This C++ module provides functions for reading and writing the FLASH chips and +SRAM in Trionic5 ECUs. (Writing the adaption data back to SRAM not done yet). + +Some functions need an additional 'bootloader' program to be sent to the T5 ECU +before they can be used. These functions are: Identifying the T5 ECU type and +FLASH chips, dumping the FLASH chips, erasing the FLASH chips, writing to the +FLASH chips and calculating the FLASH chips' checksum. + +My version of the bootloader, BOOTY.S19, includes some features not in other +bootloaders; identifying the ECU and FLASH chip types, a 'safer' way of dumping +the FLASH chips and the ability to program AMD 29F010 type FLASH chips + +******************************************************************************** + +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 "t5can.h" + +// constants +#define CMD_BUF_LENGTH 32 ///< command buffer size + +// static variables +static char cmd_buffer[CMD_BUF_LENGTH]; ///< command string buffer + +//static uint32_t cmd_addr; ///< address (optional) +//static uint32_t cmd_value; ///< value (optional) +//static uint32_t cmd_result; ///< result + +static uint32_t flash_start = 0; + +// private functions +uint8_t execute_t5_cmd(); +void t5_can_show_help(); +void t5_can_show_full_help(); + +void t5_can() { + // Start the CAN bus system + // Note that at the moment this is only for T5 ECUs at 615 kbits + can_open(); + can_set_speed(615000); + + t5_can_show_help(); + + // main loop + *cmd_buffer = '\0'; + char ret; + char rx_char; + while (true) { + // read chars from USB + // send received messages to the pc over USB connection + // This function displays any CAN messages that are 'missed' by the other functions + // Can messages might be 'missed' because they are received after a 'timeout' period + // or because they weren't expected, e.g. if the T5 ECU resets for some reason + t5_can_show_can_message(); + if (pc.readable()) { + // turn Error LED off for next command + led4 = 0; + rx_char = pc.getc(); + switch (rx_char) { + // 'ESC' key to go back to mbed Just4Trionic 'home' menu + case '\e': + can_close(); + return; + // end-of-command reached + case TERM_OK : + // execute command and return flag via USB + timer.reset(); + timer.start(); + ret = execute_t5_cmd(); + pc.putc(ret); + printf("Completed in %.1f seconds.\r\n", timer.read()); + // reset command buffer + *cmd_buffer = '\0'; + // light up LED +// ret == TERM_OK ? led_on(LED_ACT) : led_on(LED_ERR); + ret == TERM_OK ? led3 = 1 : led4 = 1; + break; + // another command char + default: + // store in buffer if space permits + if (StrLen(cmd_buffer) < CMD_BUF_LENGTH - 1) { + StrAddc(cmd_buffer, rx_char); + } + break; + } + } + } +} + +//----------------------------------------------------------------------------- +/** + Executes a command and returns result flag (does not transmit the flag + itself). + + @return command flag (success / failure) +*/ +uint8_t execute_t5_cmd() { + + +// uint8_t cmd_length = strlen(cmd_buffer); + // command groups + switch (*cmd_buffer) { +// CHECK_ARGLENGTH(0); + // Get the Symbol Table + case 's': + return t5_can_get_symbol_table() + ? TERM_OK : TERM_ERR; + case 'S': + return T5ReadCmnd(T5SYMBOLS) + ? TERM_OK : TERM_ERR; + + // Get the Trionic5 software version string + case 'v': + return t5_can_get_version() + ? TERM_OK : TERM_ERR; + case 'V': + return T5ReadCmnd(T5VERSION) + ? TERM_OK : TERM_ERR; + + // Read Adaption Data from RAM and write it to a file + case 'r': + case 'R': + return t5_can_get_adaption_data() + ? TERM_OK : TERM_ERR; + + // CR - send CR type message + case '\0': + return T5ReadCmnd(CR) + ? TERM_OK : TERM_ERR; + + // Get a single symbol from the Symbol Table + case 'a': + char symbol[40]; + T5GetSymbol(symbol); + printf("%s",symbol); + return TERM_OK; + + // Just send an 'ACK' message + case 'A': + return T5Ack() + ? TERM_OK : TERM_ERR; + + // Send a Bootloader file to the T5 ECU + case 'b': + case 'B': + return t5_can_send_boot_loader() + ? TERM_OK : TERM_ERR; + + // Get Checksum from ECU (Bootloader must be uploaded first) + case 'c': + case 'C': + return t5_can_get_checksum() + ? TERM_OK : TERM_ERR; + + // Exit the BootLoader and restart the T5 ECU + case 'q': + case 'Q': + return t5_can_bootloader_reset() + ? TERM_OK : TERM_ERR; + + // Erase the FLASH chips + case 'e': + case 'E': + return t5_can_erase_flash() + ? TERM_OK : TERM_ERR; + + // Read back the FLASH chip types + case 't': + case 'T': + return t5_can_get_start_and_chip_types(&flash_start) + ? TERM_OK : TERM_ERR; + + // DUMP the T5 ECU BIN file stored in the FLASH chips + case 'd': + // NOTE 'd' command Just4TESTING! only dumps T5.5 ECU + return t5_can_dump_flash(T55FLASHSTART) + ? TERM_OK : TERM_ERR; + case 'D': + if (!t5_can_get_adaption_data()) + return TERM_ERR; + if (!t5_can_send_boot_loader()) + return TERM_ERR; + if (!t5_can_get_start_and_chip_types(&flash_start)) { + t5_can_bootloader_reset(); + return TERM_ERR; + } + return (t5_can_dump_flash(flash_start) && t5_can_bootloader_reset()) + ? TERM_OK : TERM_ERR; + + // Send a FLASH update file to the T5 ECU + case 'f': + // NOTE 'f' command Just4TESTING! only FLASHes T5.5 ECU (with S19 type file) + return t5_can_send_flash_s19_update(T55FLASHSTART) + ? TERM_OK : TERM_ERR; + case 'F': + if (!t5_can_send_boot_loader()) + return TERM_ERR; + if (!t5_can_get_start_and_chip_types(&flash_start)) { + t5_can_bootloader_reset(); + return TERM_ERR; + } + if (!t5_can_get_checksum()) + led4 = 1; + if (!t5_can_erase_flash()) { + t5_can_bootloader_reset(); + return TERM_ERR; + } + return (t5_can_send_flash_bin_update(flash_start) && t5_can_get_checksum() && t5_can_bootloader_reset()) + ? TERM_OK : TERM_ERR; + + // Send the C3 message - should get last used address 0x7FFFF + case '3': + return t5_can_get_last_address() + ? TERM_OK : TERM_ERR; + + // Print help + case 'h': + t5_can_show_help(); + return TERM_OK; + case 'H': + t5_can_show_full_help(); + return TERM_OK; + default: + t5_can_show_help(); + break; + } + // unknown command + return TERM_ERR; +} + +// +// Trionic5ShowHelp +// +// Displays a list of things that can be done with the T5 ECU. +// +// inputs: none +// return: none +// +void t5_can_show_help() { + printf("Trionic 5 Command Menu\r\n"); + printf("======================\r\n"); + printf("D - Read SRAM adaption and DUMP T5 FLASH BIN file\r\n"); + printf("F - FLASH the update file to the T5 (and write SRAM - not done!)\r\n"); + printf("\r\n"); + printf("r - read SRAM and write it to ADAPTION.RAM file\r\n"); + printf("s - read Symbol Table and write it to SYMBOLS.TXT\r\n"); + printf("v - read T5 ECU software version, display it and write it to VERSION.TXT\r\n"); + printf("\r\n"); + printf("'ESC' - Return to Just4Trionic Main Menu\r\n"); + printf("\r\n"); + printf("h - Show this help menu\r\n"); + printf("\r\n"); + return; +} +// +// t5_can_show_full_help +// +// Displays a complete list of things that can be done with the T5 ECU. +// +// inputs: none +// return: none +// +void t5_can_show_full_help() { + printf("Trionic 5 Command Menu\r\n"); + printf("======================\r\n"); + printf("D - Read SRAM adaption and DUMP T5 FLASH BIN file\r\n"); + printf("F - FLASH the update file to the T5 (and write SRAM - not done!)\r\n"); + printf("\r\n"); + printf("b - upload and start MyBooty.S19 bootloader\r\n"); + printf("c - get T5 ECU FLASH checksum (need to upload BOOTY.S19 before using this command)\r\n"); + printf("d - dump the T5 FLASH BIN file and write it to ORIGINAL.BIN\r\n"); + printf("e - erase the FLASH chips in the T5 ECU\r\n"); + printf("f - FLASH the update file MODIFIED.S19 to the T5 ECU\r\n"); + printf("r - read SRAM and write it to ADAPTION.RAM file\r\n"); + printf("s - read Symbol Table, display it and write it to SYMBOLS.TXT\r\n"); + printf("v - read T5 ECU software version, display it and write it to VERSION.TXT\r\n"); + printf("q - exit the bootloader and reset the T5 ECU\r\n"); + printf("t - read the FLASH chip type in the T5 ECU\r\n"); + printf("3 - read the last used FLASH address in the T5 ECU\r\n"); + printf("S - send 's' message (to get symbol table)\r\n"); + printf("V - send 'S' message (to get software version)\r\n"); + printf("'Enter' Key - send an CR message\r\n"); + printf("a - send an ACK\r\n"); + printf("A - read a single symbol from the symbol table\r\n"); + printf("\r\n"); + printf("'ESC' - Return to Just4Trionic Main Menu\r\n"); + printf("\r\n"); + printf("H - Show this help menu\r\n"); + printf("\r\n"); + return; +} + +// +// t5_can_show_can_message +// +// Displays a CAN message in the RX buffer if there is one. +// +// inputs: none +// return: bool TRUE if there was a message, FALSE if no message. +// +bool t5_can_show_can_message() { + CANMessage can_MsgRx; + if (can.read(can_MsgRx)) { + printf("w%03x%d", can_MsgRx.id, can_MsgRx.len); + for (char i=0; i<can_MsgRx.len; i++) { + printf("%02x", can_MsgRx.data[i]); + } + printf(" %c ", can_MsgRx.data[2]); + printf("\r\n"); + return TRUE; + } + return FALSE; +} + +// +// t5_can_get_symbol_table +// +// Gets the T5 ECU symbol table. +// The Symbol Table is saved to a file, symbols.txt, on the mbed 'local' file system 'disk'. +// +// inputs: none +// return: bool TRUE if there all went OK, FALSE if there was an error +// +bool t5_can_get_symbol_table() { + printf("Saving the symbol table file\r\n"); + FILE *fp = fopen("/local/symbols.txt", "w"); // Open "symbols.txt" on the local file system for writing + if (!fp) { + perror ("The following error occured"); + return FALSE; + } + char symbol[40]; + T5ReadCmnd(T5SYMBOLS); + if (T5WaitResponse() != '>') { + fclose(fp); + return FALSE; + } + T5ReadCmnd(CR); + if (T5WaitResponse() != '>') { + fclose(fp); + return FALSE; + } + do { + T5GetSymbol(symbol); +// printf("%s",symbol); + if (fprintf(fp,"%s",symbol) < 0) { + fclose (fp); + printf ("ERROR Writing to the symbols.txt file!\r\n"); + return FALSE; + }; + } while (!StrCmp(symbol,"END\r\n")); + fclose(fp); + return TRUE; +} + +// +// t5_can_get_version +// +// Gets the T5 software version string. +// The software version is is sent to the PC and saved to a file, version.txt, on the mbed 'local' file system 'disk'. +// +// inputs: none +// return: bool TRUE if there all went OK, FALSE if there was an error +// +bool t5_can_get_version() { + FILE *fp = fopen("/local/version.txt", "w"); // Open "version.txt" on the local file system for writing + if (!fp) { + perror ("The following error occured"); + return FALSE; + } + char symbol[40]; + T5ReadCmnd(T5VERSION); + if (T5WaitResponse() != '>') { + fclose(fp); + return FALSE; + } + T5ReadCmnd(CR); + if (T5WaitResponse() != '>') { + fclose(fp); + return FALSE; + } + T5GetSymbol(symbol); + printf("%s",symbol); + if (fprintf(fp,"%s",symbol) < 0) { + fclose (fp); + printf ("ERROR Writing to the version.txt file!\r\n"); + return FALSE; + }; + fclose(fp); + printf("The version.txt file has been saved.\r\n"); + return TRUE; +} + +// +// Trionic5GetAdaptionData +// +// Gets the adaption data from the T5's SRAM. +// The adaption data is stored in a hex file, adaption.RAM, on the mbed 'local' file system 'disk'. +// +// Reading the Adaption data from SRAM takes about 6.5 seconds. +// +// inputs: none +// return: bool TRUE if all went OK, FALSE if there was an error. +// +bool t5_can_get_adaption_data() { + printf("Saving the SRAM adaption data.\r\n"); + FILE *fp = fopen("/local/adaption.RAM", "w"); // Open "adaption.RAM" on the local file system for writing + if (!fp) { + printf("ERROR: Unable to open a file for the adaption data!\r\n"); + return FALSE; + } + unsigned int address = 5; // Mysterious reason for starting at 5 !!! + char RAMdata[6]; + while (address < T5RAMSIZE) { + if (!t5_can_read_data(RAMdata, address)) { + fclose (fp); + printf ("Error reading from the CAN bus.\r\n"); + return FALSE; + } + address += 6; + if (fwrite(RAMdata, 1, 6, fp) != 6) { + fclose (fp); + printf ("Error writing to the SRAM adaption file.\r\n"); + return FALSE; + } + } + // There are a few more bytes to get because because the SRAM file is not an exact multiple of 6 bytes! + // the % (modulo) mathematics function tells us how many bytes there are still to get + if (!t5_can_read_data(RAMdata, (T5RAMSIZE - 1))) { + fclose (fp); + printf ("Error reading from the CAN bus.\r\n"); + return FALSE; + } + if (fwrite((RAMdata + 6 - (T5RAMSIZE % 6)), 1, (T5RAMSIZE % 6), fp) != (T5RAMSIZE % 6)) { + fclose (fp); + printf ("Error writing to the SRAM adaption file.\r\n"); + return FALSE; + } + fclose(fp); + return TRUE; +} + +// +// t5_can_send_boot_loader +// +// Sends a 'bootloader' file, booty.s19 to the T5 ECU. +// The 'bootloader' is stored on the mbed 'local' file system 'disk' and must be in S19 format. +// +// The 'bootloader' is then able to dump or reFLASH the T5 ECU FLASH chips - this is the whole point of the exercise :-) +// +// Sending the 'bootloader' to the T5 ECU takes just over 1 second. +// +// inputs: none +// return: bool TRUE if all went OK, +// FALSE if the 'bootloader' wasn't sent for some reason. +// +bool t5_can_send_boot_loader() { + printf("Starting the bootloader.\r\n"); + FILE *fp = fopen("/local/MyBooty.S19", "r"); // Open "booty.s19" on the local file system for reading + if (!fp) { + printf("Error: I could not find the bootloader file MyBooty.S19\r\n"); + return FALSE; + } + int c = 0; // for some reason fgetc returns an int instead of a char + uint8_t count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal + uint8_t asize = 0; // 2,3 or 4 bytes in address + uint32_t address = 0; // address to put S-record + uint8_t checksum = 0; // checksum check at the end of each S-record line + char msg[8]; // Construct the bootloader frame for uploading + bool sent = FALSE; + + while (!sent) { +// get characters until we get an 'S' (throws away \n,\r characters and other junk) + do c = fgetc (fp); + while (c != 'S' && c != EOF); +// if (c == EOF) return '\a'; + c = fgetc(fp); // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) +// if ((c = fgetc(fp)) == EOF) return '\a'; // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) + switch (c) { + case '0': + break; // Skip over S0 header record + + case '1': + case '2': + case '3': + asize = 1 + c - '0'; // 2, 3 or 4 bytes for address + address = 0; +// get the number of bytes (in ascii format) in this S-record line +// there must be at least the address and the checksum so return with an error if less than this! + if ((c = SRecGetByte(fp)) < (asize + 1)) break; +// if ((c = SRecGetByte(fp)) < 3) return '\a'; + count = c; + checksum = c; +// get the address + for (uint8_t i=0; i<asize; i++) { + c = SRecGetByte(fp); + checksum += c; + address <<= 8; + address |= c; + count--; + } +// send a bootloader address message + if (!t5_can_send_boot_address(address, (count-1))) return FALSE; +// get and send the bootloader frames for this S-record +// NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes +// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes +// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame. + for (uint8_t i=0; i<count-1; i++) { + c = SRecGetByte(fp); + checksum += c; + msg[1+(i%7)] = c; + if (i%7 == 0) msg[0]=i; // set the index number + if ((i%7 == 6) || (i == count - 2)) + if (!t5_can_send_boot_frame(msg)) { + fclose(fp); + return FALSE; + } + } +// get the checksum + if ((checksum += SRecGetByte(fp)) != 0xFF) { + printf("Error in S-record, checksum = %2x\r\n", checksum); + fclose(fp); + return FALSE; + } + break; + + case '5': + break; // Skip over S5 record types + + case '7': + case '8': + case '9': + asize = 11 - (c - '0'); // 2, 3 or 4 bytes for address +// get the number of bytes (in ascii format) in this S-record line there must be just the address and the checksum +// so return with an error if other than this! + if ((c = SRecGetByte(fp)) != (asize + 1)) break; +// if ((c = SRecGetByte(fp)) < 3) return '\a'; + checksum = c; +// get the address + for (uint8_t i=0; i<asize; i++) { + c = SRecGetByte(fp); + checksum += c; + address <<= 8; + address |= c; + } +// get the checksum + if ((checksum += SRecGetByte(fp)) != 0xFF) { + fclose(fp); + printf("Error in S-record, checksum = %2x\r\n", checksum); + return FALSE; + } + T5StartBootLoader(address); +// T5WaitResponsePrint(); + sent = TRUE; + break; + +// Some kind of invalid S-record type so break + default: + fclose(fp); + printf("oops - didn't recognise that S-Record \r\n"); + return FALSE; + } + } + fclose(fp); + return TRUE; +} + +// +// t5_can_get_checksum +// +// Calculates the checksum of the FLASH in the T5 ECU. +// The 'bootloader', booty.s19, must be loaded before this function can be used. +// The 'bootloader' actually calculates the checksum and compares it with the +// value stored in the 'header' region at the end of the FLASH. +// +// The bootloader sends a single CAN message with the result e.g. +// w00C8C800CAFEBABE0808 +// 00C - T5 response messages have an CAN id of 00C +// 8 - All T5 messages have a message length of 8 bytes +// C8 - This is the checksum message type +// 00 - 00 means OK, the checksum calculation matches the stored value which in this case is: +// CAFEBABE - lol :-) +// +// w00C8C801FFFFFFFF0808 +// 01 - 01 means calculated value doesn't matched the stored value +// FFFFFFFF - in this case the stored value is FFFFFFFF - the chips might be erased +// +// Calculating the checksum takes a little under 2 seconds. +// +// inputs: none +// return: bool TRUE if all went OK, +// +bool t5_can_get_checksum() { + uint32_t checksum = 0; + if (!t5_boot_checksum_command(&checksum)) { + printf("Error The ECU's checksum is wrong!\r\n"); + return FALSE; + } + printf("The FLASH checksum value is %#010x.\r\n", checksum); + return TRUE; +} + +// +// t5_can_bootloader_reset +// +// Exit the Bootloader and restart the T5 ECU +// +// inputs: none +// outputs: bool TRUE if all went OK. +// +bool t5_can_bootloader_reset() { + printf("Exiting the bootloader and restarting the T5 ECU.\r\n"); + if (!t5_boot_reset_command()) { + printf("Error trying to reset the T5 ECU!\r\n"); + return FALSE; + } + return TRUE; +} + +// +// t5_can_get_start_and_chip_types +// +// Gets the FLASH chip type fitted. +// +// NOTE the bootloader must be loaded in order to use this function. +// +// CAN messages from the T5 ECU with FLASH data look like this: +// +// C9,00,aa,aa,aa,aa,mm,dd, +// +// C9 lets us know its a FLASH id message +// +// aa,aa,aa,aa is the FLASH start address which we can use to work out if this is a T5.2 or T5.5 ECU +// 0x00020000 - T5.2 +// 0x00040000 - T5.5 +// +// mm = Manufacturer id. These can be: +// 0x89 - Intel +// 0x31 - CSI/CAT +// 0x01 - AMD +// 0x1F - Atmel +// +// dd = Device id. These can be: +// 0xB8 - Intel _or_ CSI 28F512 (Fiited by Saab in T5.2) +// 0xB4 - Intel _or_ CSI 28F010 (Fitted by Saab in T5.5) +// 0x25 - AMD 28F512 (Fiited by Saab in T5.2) +// 0xA7 - AMD 28F010 (Fitted by Saab in T5.5) +// 0x20 - AMD 29F010 (Some people have put these in their T5.5) +// 0x5D - Atmel 29C512 (Some people mave have put these in their T5.2) +// 0xD5 - Atmel 29C010 (Some people have put these in their T5.5) +// +// mm = 0xFF, dd == 0xF7 probably means that the programming voltage isn't right. +// +// Finding out which ECU type and FLASH chips are fitted takes under a second. +// +// inputs: start T5 ecu start address +// return: bool TRUE if all went OK. +// +bool t5_can_get_start_and_chip_types(uint32_t* start) { + *start = 0; + uint8_t make = 0; + uint8_t type = 0; + if (!t5_boot_get_flash_type(start, &make, &type)) { + printf("Error trying to find out the ECU's first address and FLASH chip type!\r\n"); + return FALSE; + } + printf("This is a T5.%s ECU with ", ((*start == T52FLASHSTART) ? "2" : "5")); + switch (make) { + case AMD: + printf("AMD "); + break; + case CSI: + printf("CSI "); + break; + case INTEL: + printf("INTEL "); + break; + default: + printf("UNKNOWN FLASH chips - check pin65 has enough volts!\r\n"); + } + switch (type) { + case AMD28F512: + case INTEL28F512: + printf("28F512 FLASH chips.\r\n"); + break; + case AMD28F010: + case INTEL28F010: + printf("28F010 FLASH chips.\r\n"); + break; + case AMD29F010: + printf("29F010 FLASH chips.\r\n"); + break; + default: + printf("UNKNOWN - check pin65 has enough volts!\r\n"); + return FALSE; + } + return TRUE; +} + +// +// t5_can_erase_flash +// +// Erases the FLASH Chips. +// +// NOTE the bootloader must be loaded in order to use this function. +// +// CAN messages from the T5 ECU with FLASH erase command look like this: +// +// C0,cc,08,08,08,08,08,08 +// +// C0 tells us this is a response to the FLASH erase command. +// +// cc is a code that tells us what happened: +// 00 - FLASH was erased OK +// 01 - Could not erase FLASH chips to 0xFF +// 02 - Could not write 0x00 to 28F FLASH chips +// 03 - Unrecognised FLASH chip type (or maybe programming voltage isn't right) +// 04 - Intel chips found, but unrecognised type +// 05 - AMD chips found, but unrecognised type +// 06 - CSI/Catalyst chips found, but unrecognised type +// 07 - Atmel chips found - Atmel chips don't need to be erased +// +// Erasing 28F type FLASH chips takes around 22 seconds. 29F chips take around 4 seconds. +// +// inputs: none +// return: bool TRUE if all went OK. +// +bool t5_can_erase_flash() { + printf("Erasing the FLASH chips.\r\n"); + if (!t5_boot_erase_command()) { + printf("Error The ECU's FLASH has not been erased!\r\n"); + return FALSE; + } + return TRUE; +} + +// +// t5_can_dump_flash +// +// Dumps the FLASH chip BIN file, original.bin to the mbed 'disk' +// +// NOTE the bootloader must be loaded in order to use this function. +// +// Dumping FLASH chips in a T5.5 ECU takes around 35 seconds. +// Dumping T5.2 ECUs should take about half of this time +// +// inputs: start start address of the T5.x FLASH + +// return: bool TRUE if all went OK, FALSE if there was an error. +// +bool t5_can_dump_flash(uint32_t start) { + printf("Saving the original FLASH BIN 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 FALSE; + } + uint32_t address = start + 5; // Mysterious reason for starting at 5 !!! + char FLASHdata[6]; + while (address < TRIONICLASTADDR) { + if (!t5_can_read_data(FLASHdata, address)) { + fclose (fp); + printf ("Error reading from the CAN bus.\r\n"); + return FALSE; + } + address += 6; + if (fwrite(FLASHdata, 1, 6, fp) != 6) { + fclose (fp); + printf ("Error writing to the FLASH BIN file.\r\n"); + return FALSE; + } + } + // There are a few more bytes to get because because the bin file is not an exact multiple of 6 bytes! + // the % (modulo) mathematics function tells us how many bytes there are still to get + if (!t5_can_read_data(FLASHdata, (TRIONICLASTADDR))) { + fclose (fp); + printf ("Error reading from the CAN bus.\r\n"); + return FALSE; + } + if (fwrite((FLASHdata + 6 - ((TRIONICLASTADDR - start +1) % 6)), 1, ((TRIONICLASTADDR - start +1) % 6), fp) != ((TRIONICLASTADDR - start +1) % 6)) { + fclose (fp); + printf ("Error writing to the FLASH BIN file.\r\n"); + return FALSE; + } + fclose(fp); + return TRUE; +} + + +// +// t5_can_send_flash_bin_update +// +// Sends a FLASH update file, modified.hex to the T5 ECU. +// The FLASH update file is stored on the local file system and must be in hex format. +// +// FLASHing a T5.5 ECU takes around 40 seconds. FLASHing T5.2 ECUs should take about half of this time +// +// inputs: start start address of the T5.x FLASH + +// return: bool TRUE if all went OK, +// FALSE if the FLASH update failed for some reason. +// +bool t5_can_send_flash_bin_update(uint32_t start) { + printf("Programming the FLASH chips.\r\n"); + FILE *fp = fopen("/local/modified.hex", "r"); // Open "modified.s19" on the local file system for reading + if (!fp) { + printf("Error: I could not find the BIN file MODIFIED.HEX\r\n"); + return FALSE; + } + + // 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 (start == T52FLASHSTART && (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, T52FLASHSIZE, stack_long); + return TERM_ERR; + } + if (start == T55FLASHSTART && (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, T55FLASHSIZE, stack_long); + return TERM_ERR; + } + + char msg[8]; // Construct the bootloader frame for uploading + uint32_t curr_addr = start; // address to put FLASH data + uint8_t byte_value = 0; + + while (curr_addr <= TRIONICLASTADDR) { + +// send a bootloader address message + if (!t5_can_send_boot_address(curr_addr, 0x80)) { + fclose(fp); + printf("Error sending CAN message"); + return FALSE; + } + curr_addr += 0x80; +// Construct and send the bootloader frames +// NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes +// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes +// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame. + for (uint8_t i=0; i<0x80; i++) { + if (!fread(&byte_value,1,1,fp)) { + fclose(fp); + printf("Error reading the BIN file MODIFIED.HEX"); + return FALSE; + } + msg[1+(i%7)] = byte_value; + if (i%7 == 0) msg[0]=i; // set the index number + if ((i%7 == 6) || (i == 0x80 - 1)) + if (!t5_can_send_boot_frame(msg)) { + fclose(fp); + printf("Error sending CAN message"); + return FALSE; + } + } + } + fclose(fp); + return TRUE; +} + +// +// t5_can_send_flash_s19_update +// +// Sends a FLASH update file, modified.s19 to the T5 ECU. +// The FLASH update file is stored on the local file system and must be in S19 format. +// +// FLASHing a T5.5 ECU takes around 60 seconds. FLASHing T5.2 ECUs should take about half of this time +// +// inputs: start start address of the T5.x FLASH + +// return: bool TRUE if all went OK, +// FALSE if the FLASH update failed for some reason. +// +bool t5_can_send_flash_s19_update(uint32_t start) { + printf("Programming the FLASH chips.\r\n"); + FILE *fp = fopen("/local/modified.s19", "r"); // Open "modified.s19" on the local file system for reading + if (!fp) { + printf("Error: I could not find the BIN file MODIFIED.S19\r\n"); + return FALSE; + } + int c = 0; // for some reason fgetc returns an int instead of a char + uint8_t count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal + uint8_t asize = 0; // 2,3 or 4 bytes in address + uint32_t address = 0; // address to put S-record + uint8_t checksum = 0; // checksum check at the end + char msg[8]; // Construct the bootloader frame for uploading + bool sent = FALSE; + + while (!sent) { + + do c = fgetc (fp); // get characters until we get an 'S' (throws away \n,\r characters and other junk) + while (c != 'S' && c != EOF); +// if (c == EOF) return '\a'; + c = fgetc(fp); // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) +// if ((c = fgetc(fp)) == EOF) return '\a'; // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) + switch (c) { + case '0': + break; // Skip over S0 header record + + case '1': + case '2': + case '3': + asize = 1 + c - '0'; // 2, 3 or 4 bytes for address + address = 0; +// get the number of bytes (in ascii format) in this S-record line +// there must be at least the address and the checksum so return with an error if less than this! + if ((c = SRecGetByte(fp)) < (asize + 1)) { + fclose(fp); + printf("Error in S-record address"); + return FALSE; + } + count = c; + checksum = c; +// get the address + for (uint8_t i=0; i<asize; i++) { + c = SRecGetByte(fp); + checksum += c; + address <<= 8; + address |= c; + count--; + } +// send a bootloader address message - Adding the start address that was supplied (for T5.2/T5.5) + if (!t5_can_send_boot_address((address + start), (count - 1))) { + fclose(fp); + printf("Error sending CAN message"); + return FALSE; + } +// get and send the bootloader frames for this S-record +// NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes +// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes +// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame. + for (uint8_t i=0; i<count-1; i++) { + c = SRecGetByte(fp); + checksum += c; + msg[1+(i%7)] = c; + if (i%7 == 0) msg[0]=i; // set the index number + if ((i%7 == 6) || (i == count - 2)) + if (!t5_can_send_boot_frame(msg)) { + fclose(fp); + printf("Error sending CAN message"); + return FALSE; + } + } +// get the checksum + if ((checksum += SRecGetByte(fp)) != 0xFF) { + fclose(fp); + printf("Error in S-record, checksum = %2x\r\n", checksum); + return FALSE; + } + break; + + case '5': + break; // Skip over S5 record types + + case '7': + case '8': + case '9': + sent = TRUE; + break; + +// Some kind of invalid S-record type so break + default: + printf("oops - didn't recognise that S-Record\r\n"); + fclose(fp); + return FALSE; + } + } + fclose(fp); + return TRUE; +} + +// +// t5_can_get_last_address +// +// Sends a C3 Message to the T5 ECU. The reply should contain the last used FLASH address +// which is always 0x0007FFFF +// +// The last 2 bytes of the message might be useful to work out whether or not the bootloader +// has been loaded. The 'mode' value will be 0x0808 when the bootloader is running or 0x89b8 +// when it isn't. +// +// inputs: none +// return: bool TRUE if all went OK, +// +bool t5_can_get_last_address() { + uint32_t last_address = 0; + uint16_t mode = 0; + if (!t5_boot_c3_command(&last_address, &mode)) { + printf("Error trying to find out the ECU's last address and mode!\r\n"); + return FALSE; + } + printf("The Last used FLASH address is: %#010x, mode %#06x\r\n", last_address, mode); + return TRUE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/t5can.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,46 @@ +/******************************************************************************* + +t5can.h - information and definitions needed for doing things with the T5 ECU +(c) 2010 by Sophie Dexter + +******************************************************************************** + +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. + +*******************************************************************************/ + +#ifndef __T5CAN_H__ +#define __T5CAN_H__ + +#include "mbed.h" +#include "CAN.h" + +#include "common.h" +#include "strings.h" +#include "t5utils.h" +#include "srecutils.h" + +#define T5SYMBOLS 'S' +#define T5VERSION 's' +#define T5WRITE 'W' + +extern void t5_can(); + +void t5_can_show_help(); +bool t5_can_show_can_message(); +bool t5_can_get_symbol_table(); +bool t5_can_get_version(); +bool t5_can_get_adaption_data(); +bool t5_can_send_boot_loader(); +bool t5_can_get_checksum(); +bool t5_can_bootloader_reset(); +bool t5_can_get_start_and_chip_types(uint32_t* start); +bool t5_can_erase_flash(); +bool t5_can_dump_flash(uint32_t start); +bool t5_can_send_flash_s19_update(uint32_t start); +bool t5_can_send_flash_bin_update(uint32_t start); +bool t5_can_get_last_address(); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/t5utils.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,411 @@ +/******************************************************************************* + +t5utils.cpp +(c) 2010 by Sophie Dexter + +This C++ module provides functions for communicating simple messages to and from +the T5 ECU + +******************************************************************************** + +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 "t5utils.h" + +// +// T5Open enables the CAN chip and sets the CAN speed to 615 kbits. +// +// This function is a 'quick fix' for now. +// +// inputs: none +// return: bool TRUE if all went OK, +// +bool T5Open() { + can_open (); + return TRUE; +} + +// +// T5Close disables the CAN chip. +// +// This function is a 'quick fix' for now. +// +// inputs: none +// return: bool TRUE if all went OK, +// +bool T5Close() { + can_close (); + return TRUE; +} + +// +// T5WaitResponse +// +// Waits for a response message with the correct message id from the T5 ECU. +// The response is a single ascii character from the symboltable. +// +// Returns an error ('BELL' character) if: +// a response is not received before the timeout +// the message length is less than 8 bytes (all messages should be 8 bytes) +// the message type is incorrect +// +// inputs: none +// return: a single char that is the response from the T5 ECU +// +char T5WaitResponse() { + char T5RxMsg[8]; + if (!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return '\a'; + if (T5RxMsg[0] != 0xC6) return '\a'; + return T5RxMsg[2]; +} + +// +// +// T5WaitResponsePrint +// +// Waits for a response message with the correct message id from the T5 ECU and displays the whole message: +// +// wiiildddddddddddddddd +// iii - is the CAN message id +// l - is the message length, should always be 8 for T5 messages +// dd,dd,dd,dd,dd,dd,dd,dd are the CAN message data bytes +// +// Returns an error if: +// a response is not received before the timeout +// the message length is less than 8 bytes (all messages should be 8 bytes) +// the message type is incorrect +// +// Inputs: none +// return: bool TRUE if a qualifying message was received +// FALSE if a message wasn't received in time, had the wrong id etc... +// +bool T5WaitResponsePrint() { + char T5RxMsg[8]; + if (!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; + printf("w%03x8", RESPID); + for (char i=0; i<8; i++) { + printf("%02x", T5RxMsg[i]); + } + printf("\n\r"); + return TRUE; +} + +// T5GetSymbol +// +// Reads a single symbol name (in the symbol table) from the T5 ECU. +// T5GetSymbol sends ACK messages to the T5 ECU and stores the +// reply characters in a string until a '\n' character is received +// when the function returns with the pointer to that string. +// +// inputs: a pointer to the string used to store the symbol name. +// return: a pointer to the string used to store the symbol name. +// +char *T5GetSymbol(char *s) { + do { + if (T5Ack()) { + } + *s = T5WaitResponse(); + } while (*s++ != '\n'); + *s = '\0'; + return s; +} + +// T5ReadCmnd +// +// Sends a 'read' type command to the T5 ECU. 'read' commands are used to read something from the T5 ECU. +// +// inputs: a 'char' which is the type of 'read' requested (e.g. symbol table, version etc). +// return: bool TRUE if the message was sent within the timeout period, +// FALSE if the message couldn't be sent. +// +bool T5ReadCmnd(char c) { + char T5TxMsg[] = T5_RDCMND; + T5TxMsg[1] = c; + return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); +} + +// +// T5WriteCmnd is unfinished +// +bool T5WriteCmnd(unsigned int addr, char data) { + return FALSE; +} + + + +// t5_can_read_data +// +// Reads 6 bytes of the data from the SRAM or FLASH in the T5 ECU. +// +// There is something back-to-front about the way this works, but it does :-) +// +// inputs: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. +// the address to read SRAM data from in the T5 ECU +// return: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. +// bool TRUE if the message was sent within the timeout period, +// FALSE if the message couldn't be sent. +// +bool t5_can_read_data(char *data, uint32_t addr) { + + // send a can message to the T5 with the address we want to read from + char T5TxMsg[] = T5RAMCMND; + T5TxMsg[1] = ((uint8_t)(addr >> 24)); // high high byte of address + T5TxMsg[2] = ((uint8_t)(addr >> 16)); // high low byte of address + T5TxMsg[3] = ((uint8_t)(addr >> 8)); // low high byte of address + T5TxMsg[4] = ((uint8_t)(addr)); // low low byte of address + // if the message cannot be sent then there is a problem + if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) + return FALSE; + // wait for the T5 to reply with some data + char T5RxMsg[8]; + // if a message is not received, has the wrong type or indicates an error then there is a problem + if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) + return FALSE; + for (int i=2; i<8; i++) + data[7-i] = T5RxMsg[i]; + return TRUE; +} + +// T5Ack +// +// Sends an 'ACK' message to the T5 ECU to prompt the T5 to send the next +// ascii character from the symboltable +// +// Returns an error if: +// the 'ACK' message cannot be sent before the timeout +// +// inputs: none +// return: bool TRUE if message was sent OK, +// FALSE if message could not be sent. + +bool T5Ack() { + char T5TxMsg[] = T5ACKCMND; + return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); +} + +// +// t5_can_send_boot_address +// +// Send an address where 'bootloader' or FLASH CAN messages are uploaded to. +// The number of bytes (up to 0x7F) that will be sent in the following CAN messages is also sent. +// +// inputs: an unsigned int, the address where messages should be sent. +// an int, the number of bytes (up to 0x7F) that will be sent in the following CAN messages. +// return: bool TRUE if message was sent OK, +// FALSE if message could not be sent. +// +bool t5_can_send_boot_address(uint32_t addr, uint8_t len) { + // send a can message to the T5 with the address and number of bytes we are going to send + char T5TxMsg[] = T5_BTCMND; + T5TxMsg[1] = ((uint8_t)(addr >> 24)); // high high byte of address + T5TxMsg[2] = ((uint8_t)(addr >> 16)); // high low byte of address + T5TxMsg[3] = ((uint8_t)(addr >> 8)); // low high byte of address + T5TxMsg[4] = ((uint8_t)(addr)); // low low byte of address + T5TxMsg[5] = (len); // number of bytes to upload (sent in following messages) + // if the message cannot be sent then there is a problem + if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) + return FALSE; + // wait for the T5 to reply + char T5RxMsg[8]; + // if a message is not received, has the wrong type or indicates an error then there is a problem + return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) + ? FALSE : TRUE; +} + +// +// t5_can_send_boot_frame +// +// Upload 'bootloader' or new FLASH byts to T5 ECU in CAN messages +// +// The CAN messages are made up of 1 byte which is added to the address given in the T5SendBootAddress meaassge +// followed by 7 bytes of data. +// The first byte normally starts at 0x00 and increases by 7 in following messages until another T5SendBootAddress message is sent e.g. +// 00,dd,dd,dd,dd,dd,dd,dd,dd 'dd' bytes are the data bytes, 7 in each CAN message except the last one which may have less. +// 07,dd,dd,dd,dd,dd,dd,dd,dd +// 0E,dd,dd,dd,dd,dd,dd,dd,dd (0x0E is 14) +// 15,dd,dd,dd,dd,dd,dd,dd,dd (0x15 is 21) +// etc. +// +// inputs: a pointer to an array of 8 bytes to be sent to the T5 ECU SRAM or FLASH. +// return: bool TRUE if message was sent OK, +// FALSE if message could not be sent. +// +bool t5_can_send_boot_frame (char *T5TxMsg) { + // send a can message to the T5 with the bytes we are sending + if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) + return FALSE; + // wait for the T5 to reply + char T5RxMsg[8]; + // if a message is not received, has the wrong type or indicates an error then there is a problem + return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) + ? FALSE : TRUE; +} + +// +// T5StartBootLoader +// +// Send the jump to address to the T5 ECU for starting the 'bootloader'. +// The jump address must be somewhere in RAM (addresses 0x0000 to 0x8000). +// (The start address comes from the S7/8/9 line in the S19 file.) +// +// inputs: an unsigned int, the address to jump to start of 'bootloader'. +// return: bool TRUE if message was sent OK, +// FALSE if message could not be sent. +// +bool T5StartBootLoader (uint32_t addr) { + char T5TxMsg[] = T5JMPCMND; + T5TxMsg[3] = ((uint8_t)(addr >> 8)); // low byte of address + T5TxMsg[4] = ((uint8_t)(addr)); // high byte of address + return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); +} + +// +// t5_boot_checksum_command +// +// Send the checksum command to Bootloader +// +// inputs: none +// return: bool TRUE if message was sent OK, +// FALSE if message could not be sent. +// +bool t5_boot_checksum_command(uint32_t* result) { + *result = 0; + // send a can message to the T5 requesting that it calculates the BIN file checksum + char T5TxMsg[] = T5SUMCMND; + if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) + return FALSE; + // wait for the T5 to reply + char T5RxMsg[8]; + // if a message is not received, has the wrong type or indicates an error then there is a problem + if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5CHECKSUMTIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) + return FALSE; +// get the checksum + for (uint8_t i=0; i<4; i++) { + *result <<= 8; + *result |= T5RxMsg[i+2]; + } + return TRUE; +} + +// +// t5_boot_reset_command +// +// Send 'exit and restart T5' command to the Bootloader +// +// inputs: none +// return: bool TRUE if message was sent OK, +// FALSE if message could not be sent. +// +bool t5_boot_reset_command() { + // send a can message to the T5 telling it to reset the ECU + char T5TxMsg[] = T5RSTCMND; + if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) + return FALSE; + // wait for the T5 to reply + char T5RxMsg[8]; + // if a message is not received, has the wrong type or indicates an error then there is a problem + if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) + return FALSE; + // wait for the T5 to reset + // if a message is not received, has the wrong type or indicates an error then there is a problem + return (!can_wait_timeout(RSETID, T5RxMsg, 8, T5MESSAGETIMEOUT)) + ? FALSE : TRUE; +} + +//----------------------------------------------------------------------------- +/** + t5_boot_get_flash_type + Send 'get FLASH chip types' command to the Bootloader + + @param result start address of T5.x FLASH + make FLASH chip manufacturer code + type FLASH chip type code + + @return bool TRUE if message was sent OK, + FALSE if message could not be sent. +*/ +bool t5_boot_get_flash_type(uint32_t* result, uint8_t* make, uint8_t* type) { + *result = 0; + *make = 0; + *type = 0; + // send a can message to the T5 requesting that it tells us the type of FLASH chips + char T5TxMsg[] = T5TYPCMND; + if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) + return FALSE; + // wait for the T5 to reply + char T5RxMsg[8]; + // if a message is not received, has the wrong type or indicates an error then there is a problem + if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) + return FALSE; + // get the start address + for (uint8_t i=0; i<4; i++) { + *result <<= 8; + *result |= T5RxMsg[i+2]; + } + // get the manufacture code + *make = T5RxMsg[6]; + // get the FLASH type code + *type = T5RxMsg[7]; + return TRUE; +} + +//----------------------------------------------------------------------------- +/** + t5_boot_erase_command + Send 'erase FLASH chip types' command to the Bootloader + + @param none + + @return bool TRUE if message was sent OK, + FALSE if message could not be sent. +*/ +bool t5_boot_erase_command() { + // send a can message to the T5 telling it to erase the FLASH chips + char T5TxMsg[] = T5ERACMND; + if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) + return FALSE; + // wait for the T5 to reply + char T5RxMsg[8]; + // if a message is not received, has the wrong type or indicates an error then there is a problem + return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5ERASETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) + ? FALSE : TRUE; +} + +//----------------------------------------------------------------------------- +/** + t5_boot_c3_command + Send 'C3 - Get last address' command to the Bootloader + + @param result last address of T5 FLASH + mode might indicate if bootloader is loaded + + @return bool TRUE if message was sent OK, + FALSE if message could not be sent. +*/ +bool t5_boot_c3_command(uint32_t* result, uint16_t* mode) { + *result = 0; + *mode = 0; + // send a can message to the T5 requesting that it tells us the last address of FLASH + char T5TxMsg[] = T5EOFCMND; + if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) + return FALSE; + // wait for the T5 to reply + char T5RxMsg[8]; + // if a message is not received, has the wrong type or indicates an error then there is a problem + if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) + return FALSE; +// get the checksum + for (uint8_t i=0; i<4; i++) { + *result <<= 8; + *result |= T5RxMsg[i+2]; + } + for (uint8_t i=0; i<2; i++) { + *mode <<= 8; + *mode |= T5RxMsg[i+6]; + } + return TRUE; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/t5utils.h Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,61 @@ + +// t5utils.h - information and definitions needed for communicating with the T5 ECU + +// (C) 2010, Sophie Dexter + +#ifndef __T5UTILS_H__ +#define __T5UTILS_H__ + +#include "mbed.h" + +#include "common.h" +#include "canutils.h" + +#define CMNDID 0x05 +#define ACK_ID 0x06 +#define RESPID 0x0C +#define RSETID 0x08 + +#define T5_RDCMND {0xC4,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} // C4 Command template for reading something from the T5 ECU +#define T5_WRCMND {0xC4,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C4 Command template for writing something to the T5 ECU +#define T5ACKCMND {0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C6 Command for acknowledging receipt of last message from T5 ECU or + // asking it to send some more data (e.g. symbol table) I'm not sure which :lol: +#define T5_BTCMND {0xA5,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // A5 Command template for sending a bootloader to the T5 ECU +#define T5JMPCMND {0xC1,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C1 Command template for starting a bootloader that has been sent to the T5 ECU +#define T5EOFCMND {0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C3 Command for reading back the last address of FLASH in the T5 ECU +#define T5A_DCMND {0xC5,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C5 Command for setting analogue to digital registers (don't know what this is for) +#define T5RAMCMND {0xC7,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C7 Command for reading T5 RAM (all the symbols and adaption data is in RAM) + + +#define T5ERACMND {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C0 Command for erasing T5 FLASH Chips !!! (Bootloader must be loaded before using) +#define T5RSTCMND {0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C2 Command for exiting the Bootloader and restarting the T5 ECU (Bootloader must be loaded before using) +#define T5SUMCMND {0xC8,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C8 Command for reading T5 FLASH Checksum (Bootloader must be loaded before using) +#define T5TYPCMND {0xC9,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // C9 Command for reading T5 FLASH Chip types (Bootloader must be loaded before using) + +#define T5STARTMSG {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00} // T5 sends this message whenever the ignition is turned on? - message id is RESPID +#define T5RESETMSG {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} // T5 sends this message to say that it has reset - message id is RSETID + +#define T5MESSAGETIMEOUT 500 // 500 milliseconds (half a second) - Seems to be plenty of time to wait for messages on the CAN bus +#define T5CHECKSUMTIMEOUT 2000 // 2 seconds (2,000 milliseconds) - Usually takes less than a second so allowing 2 is plenty +#define T5ERASETIMEOUT 40000 // 40 seconds (60,000 milliseconds) - Usually takes less than 20 seconds so allowing 40 is plenty + +extern bool T5Open(); +extern bool T5Close(); +extern char T5WaitResponse(); +extern bool T5WaitResponsePrint(); +extern char *T5GetSymbol(char *a_symbol); +extern bool T5ReadCmnd(char c); +extern bool T5WriteCmnd(uint32_t addr, char data); +extern bool t5_can_read_data(char *data, uint32_t addr); +extern bool T5Ack(); +extern bool t5_can_send_boot_address(uint32_t addr, uint8_t len); +extern bool t5_can_send_boot_frame(char *T5TxMsg); +extern bool T5StartBootLoader (uint32_t addr); + +extern bool t5_boot_checksum_command(uint32_t* result); +extern bool t5_boot_reset_command(); +extern bool t5_boot_get_flash_type(uint32_t* result, uint8_t* make, uint8_t* type); +extern bool t5_boot_erase_command(); +extern bool t5_boot_c3_command(uint32_t* result, uint16_t* mode); + +#endif \ No newline at end of file