diff --git a/c/rs485-boot/README.md b/c/rs485-boot/README.md index 3ddab30..7141746 100644 --- a/c/rs485-boot/README.md +++ b/c/rs485-boot/README.md @@ -6,7 +6,9 @@ Ядро не обращается к регистрам МК. Проект передаёт ему принятые байты через `rs485_boot_feed()` и реализует callbacks Flash/передачи из `rs485_boot_port_t`. -Готовые bare-metal порты находятся в `ports/stm32f103` и `ports/stm32g474vet`. +Готовые порты находятся в `ports/stm32f103`, `ports/stm32g474vet`, +`ports/tms320f2812` и `ports/tms320f28335`. TI-порты используют общее ядро +`ports/c28x` для ABI C28x с 16-битным `char` и умеют зеркалировать Flash в RAM. Важно: линии A/B должны иметь терминацию и fail-safe bias. Порт держит DE активным до флага физического завершения передачи TC, затем возвращается в RX. diff --git a/c/rs485-boot/ports/c28x/rs_boot_transport.c b/c/rs485-boot/ports/c28x/rs_boot_transport.c new file mode 100644 index 0000000..a783384 --- /dev/null +++ b/c/rs485-boot/ports/c28x/rs_boot_transport.c @@ -0,0 +1,130 @@ +#include "rs_boot_transport.h" + +#define SOF0 0xA5U +#define SOF1 0x5AU +#define VERSION 1U +#define HEADER 8U +#define CRC_SIZE 4U +#define MSG_BEGIN 0x0BU +#define MSG_DATA 0x0CU +#define MSG_END 0x0DU +#define MSG_ABORT 0x0EU +#define MSG_STATUS 0x0FU +#define MSG_NACK 0x80U + +static rsbt_u16_t u16(const rsbt_byte_t *p) +{ return (p[0] & 0xFFU) | ((p[1] & 0xFFU) << 8); } + +static rsbt_u32_t u32(const rsbt_byte_t *p) +{ + return (rsbt_u32_t)(p[0] & 0xFFU) | + ((rsbt_u32_t)(p[1] & 0xFFU) << 8) | + ((rsbt_u32_t)(p[2] & 0xFFU) << 16) | + ((rsbt_u32_t)(p[3] & 0xFFU) << 24); +} + +static void put32(rsbt_byte_t *p, rsbt_u32_t v) +{ + p[0] = (rsbt_byte_t)(v & 0xFFU); p[1] = (rsbt_byte_t)((v >> 8) & 0xFFU); + p[2] = (rsbt_byte_t)((v >> 16) & 0xFFU); p[3] = (rsbt_byte_t)((v >> 24) & 0xFFU); +} + +rsbt_u32_t rsbt_crc32(const rsbt_byte_t *p, rsbt_u16_t n) +{ + rsbt_u32_t crc = 0xFFFFFFFFUL; + rsbt_u16_t i, bit; + for (i = 0U; i < n; ++i) { + crc ^= (rsbt_u32_t)(p[i] & 0xFFU); + for (bit = 0U; bit < 8U; ++bit) + crc = (crc >> 1) ^ ((crc & 1U) ? 0xEDB88320UL : 0U); + } + return crc ^ 0xFFFFFFFFUL; +} + +void rsbt_abort(rsbt_t *b) +{ + if (!b) return; + b->state = RSBT_IDLE; b->image_size = 0UL; b->flags = 0U; + b->image_crc = 0UL; b->next_offset = 0UL; +} + +int rsbt_init(rsbt_t *b, const rsbt_config_t *c, const rsbt_port_t *p, void *u) +{ + rsbt_u16_t i; + if (!b || !c || !p || !c->app_size || !p->transmit || !p->erase || !p->write || !p->read) return 0; + for (i = 0U; i < RSBT_MAX_FRAME; ++i) { b->parser[i] = 0U; b->tx[i] = 0U; } + b->config = *c; b->port = *p; b->user = u; b->parser_length = 0U; b->crc_errors = 0UL; + if (!b->config.max_block || b->config.max_block > RSBT_MAX_BLOCK) b->config.max_block = RSBT_MAX_BLOCK; + rsbt_abort(b); return 1; +} + +static int send_frame(rsbt_t *b, rsbt_byte_t type, rsbt_u16_t seq, + const rsbt_byte_t *payload, rsbt_u16_t size) +{ + rsbt_u16_t i, total; rsbt_u32_t crc; + if (size > RSBT_MAX_PAYLOAD) return 0; + total = HEADER + size + CRC_SIZE; + b->tx[0]=SOF0; b->tx[1]=SOF1; b->tx[2]=VERSION; b->tx[3]=type; + b->tx[4]=(seq>>8)&0xFFU; b->tx[5]=seq&0xFFU; + b->tx[6]=(size>>8)&0xFFU; b->tx[7]=size&0xFFU; + for(i=0U;itx[HEADER+i]=payload[i]&0xFFU; + crc=rsbt_crc32(&b->tx[2],6U+size); put32(&b->tx[HEADER+size],crc); + return b->port.transmit(b->user,b->tx,total); +} + +static void nack(rsbt_t *b, rsbt_byte_t req, rsbt_u16_t seq, rsbt_u16_t result) +{ + rsbt_byte_t p[3]; p[0]=result&0xFFU; p[1]=(result>>8)&0xFFU; p[2]=req; + (void)send_frame(b,MSG_NACK,seq,p,3U); +} + +static int matches(rsbt_t *b, rsbt_u32_t off, const rsbt_byte_t *p, rsbt_u16_t n) +{ + rsbt_u16_t done=0U,i,take; + while(done32U)take=32U; + if(!b->port.read(b->user,off+done,b->scratch,take))return 0; + for(i=0U;iscratch[i]&0xFFU)!=(p[done+i]&0xFFU))return 0; + done+=take;} return 1; +} + +static void process(rsbt_t *b, rsbt_byte_t type, rsbt_u16_t seq, + const rsbt_byte_t *p, rsbt_u16_t size) +{ + rsbt_u32_t off,base; rsbt_u16_t n,sum,i; + if(type==MSG_BEGIN){if(size!=16U){nack(b,type,seq,2U);return;} + b->image_size=u32(p);b->image_crc=u32(&p[4]);b->flags=p[8]&RSBT_FLAG_MIRROR_RAM;base=u32(&p[12]); + if((b->flags&RSBT_FLAG_MIRROR_RAM)&&!b->port.write_ram){nack(b,type,seq,0x11U);return;} + if(!b->image_size||b->image_size>b->config.app_size||(base&&base!=b->config.app_address)){nack(b,type,seq,1U);return;} + b->next_offset=0UL;b->state=RSBT_RECEIVING; + if(!b->port.erase(b->user,b->image_size)){b->state=RSBT_FAILED;nack(b,type,seq,7U);return;} + put32(b->scratch,0UL);(void)send_frame(b,type,seq,b->scratch,4U);return;} + if(type==MSG_DATA){if(b->state!=RSBT_RECEIVING||size<8U){nack(b,type,seq,5U);return;} + off=u32(p);n=u16(&p[4]);sum=0U;for(i=0U;ib->config.max_block||size!=8U+n||off>b->image_size||n>b->image_size-off){nack(b,type,seq,2U);return;} + if(sum!=u16(&p[6])){nack(b,type,seq,1U);return;} + if(offnext_offset){if(off+n>b->next_offset||!matches(b,off,&p[8],n)){nack(b,type,seq,1U);return;}} + else {if(off!=b->next_offset||!b->port.write(b->user,off,&p[8],n)|| + ((b->flags&RSBT_FLAG_MIRROR_RAM)&&!b->port.write_ram(b->user,off,&p[8],n))){b->state=RSBT_FAILED;nack(b,type,seq,7U);return;}b->next_offset+=n;} + put32(b->scratch,b->next_offset);(void)send_frame(b,type,seq,b->scratch,4U);return;} + if(type==MSG_END){if(b->state!=RSBT_RECEIVING||size!=8U||u32(p)!=b->image_size||u32(&p[4])!=b->image_crc||b->next_offset!=b->image_size||(b->port.image_valid&&!b->port.image_valid(b->user,b->image_size,b->image_crc))){b->state=RSBT_FAILED;nack(b,type,seq,1U);return;} + b->state=RSBT_READY;(void)send_frame(b,type,seq,0,0U);if(b->port.reboot)b->port.reboot(b->user);return;} + if(type==MSG_ABORT){rsbt_abort(b);(void)send_frame(b,type,seq,0,0U);return;} + if(type==MSG_STATUS){b->scratch[0]=b->state;put32(&b->scratch[1],b->next_offset);b->scratch[5]=b->flags;(void)send_frame(b,type,seq,b->scratch,6U);return;} + nack(b,type,seq,0x11U); +} + +static void discard(rsbt_t *b, rsbt_u16_t n) +{ rsbt_u16_t i;if(n>=b->parser_length){b->parser_length=0U;return;}for(i=n;iparser_length;++i)b->parser[i-n]=b->parser[i];b->parser_length-=n; } + +void rsbt_feed(rsbt_t *b, rsbt_byte_t byte) +{ + rsbt_u16_t payload,total,seq; rsbt_u32_t got; + if(!b)return;if(b->parser_length==RSBT_MAX_FRAME)b->parser_length=0U; + b->parser[b->parser_length++]=byte&0xFFU; + for(;;){while(b->parser_length>=2U&&(b->parser[0]!=SOF0||b->parser[1]!=SOF1))discard(b,1U); + if(b->parser_lengthparser[2]!=VERSION){discard(b,1U);continue;} + payload=((b->parser[6]&0xFFU)<<8)|(b->parser[7]&0xFFU);if(payload>RSBT_MAX_PAYLOAD){discard(b,1U);continue;} + total=HEADER+payload+CRC_SIZE;if(b->parser_lengthparser[HEADER+payload]); + if(got!=rsbt_crc32(&b->parser[2],6U+payload)){++b->crc_errors;discard(b,1U);continue;} + seq=((b->parser[4]&0xFFU)<<8)|(b->parser[5]&0xFFU);process(b,b->parser[3],seq,&b->parser[HEADER],payload);discard(b,total);} +} diff --git a/c/rs485-boot/ports/c28x/rs_boot_transport.h b/c/rs485-boot/ports/c28x/rs_boot_transport.h new file mode 100644 index 0000000..7447509 --- /dev/null +++ b/c/rs485-boot/ports/c28x/rs_boot_transport.h @@ -0,0 +1,62 @@ +#ifndef RS_BOOT_TRANSPORT_H +#define RS_BOOT_TRANSPORT_H + +/* + * ProtoCAN RS boot transport for TI C28x. + * A C28x char is 16 bits, therefore every wire byte is stored in the low + * eight bits of rsbt_byte_t. Never use sizeof() as a wire-byte count. + */ +typedef unsigned int rsbt_byte_t; +typedef unsigned int rsbt_u16_t; +typedef unsigned long rsbt_u32_t; + +#define RSBT_MAX_PAYLOAD 512U +#define RSBT_MAX_FRAME (8U + RSBT_MAX_PAYLOAD + 4U) +#define RSBT_MAX_BLOCK (RSBT_MAX_PAYLOAD - 8U) +#define RSBT_FLAG_MIRROR_RAM 0x01U + +typedef enum { + RSBT_IDLE = 0U, + RSBT_RECEIVING = 1U, + RSBT_READY = 2U, + RSBT_FAILED = 3U +} rsbt_state_t; + +typedef struct { + int (*transmit)(void *, const rsbt_byte_t *, rsbt_u16_t); + int (*erase)(void *, rsbt_u32_t); + int (*write)(void *, rsbt_u32_t, const rsbt_byte_t *, rsbt_u16_t); + int (*read)(void *, rsbt_u32_t, rsbt_byte_t *, rsbt_u16_t); + int (*write_ram)(void *, rsbt_u32_t, const rsbt_byte_t *, rsbt_u16_t); + int (*image_valid)(void *, rsbt_u32_t, rsbt_u32_t); + void (*reboot)(void *); +} rsbt_port_t; + +typedef struct { + rsbt_u32_t app_address; + rsbt_u32_t app_size; + rsbt_u16_t max_block; +} rsbt_config_t; + +typedef struct { + rsbt_config_t config; + rsbt_port_t port; + void *user; + rsbt_byte_t parser[RSBT_MAX_FRAME]; + rsbt_byte_t tx[RSBT_MAX_FRAME]; + rsbt_byte_t scratch[32]; + rsbt_u16_t parser_length; + rsbt_u32_t image_size; + rsbt_u32_t image_crc; + rsbt_u32_t next_offset; + rsbt_u32_t crc_errors; + rsbt_byte_t flags; + rsbt_state_t state; +} rsbt_t; + +int rsbt_init(rsbt_t *, const rsbt_config_t *, const rsbt_port_t *, void *); +void rsbt_feed(rsbt_t *, rsbt_byte_t); +void rsbt_abort(rsbt_t *); +rsbt_u32_t rsbt_crc32(const rsbt_byte_t *, rsbt_u16_t); + +#endif diff --git a/c/rs485-boot/ports/tms320f2812/README.md b/c/rs485-boot/ports/tms320f2812/README.md new file mode 100644 index 0000000..add3dac --- /dev/null +++ b/c/rs485-boot/ports/tms320f2812/README.md @@ -0,0 +1,4 @@ +# TMS320F2812 +BALZAM adapter using the common C28x transport, existing `RS485` helpers and +`flash_tools`. BEGIN byte 8 bit 0 mirrors blocks to RAM while Flash remains the +persistent recovery source. diff --git a/c/rs485-boot/ports/tms320f2812/rs_boot_port_f2812.c b/c/rs485-boot/ports/tms320f2812/rs_boot_port_f2812.c new file mode 100644 index 0000000..6f45b92 --- /dev/null +++ b/c/rs485-boot/ports/tms320f2812/rs_boot_port_f2812.c @@ -0,0 +1,99 @@ +#include "DSP281x_Device.h" +#include "RS485.h" +#include "flash_tools.h" +#include "rs_boot_port_f2812.h" + +static rsbt_t boot; + +/* Sector sizes of the external flash, in 16-bit words. */ +static const unsigned long sectors[] = { + 0x8000UL,0x8000UL,0x8000UL,0x8000UL,0x8000UL,0x8000UL,0x8000UL, + 0x8000UL,0x8000UL,0x8000UL,0x8000UL,0x8000UL,0x8000UL,0x8000UL, + 0x4000UL,0x1000UL,0x1000UL,0x2000UL +}; + +static int port_tx(void *user, const rsbt_byte_t *data, rsbt_u16_t length) +{ + rsbt_u16_t i; (void)user; + RS_Line_to_send(COM_1); RS_SetBitMode(&rs_a,8); + for(i=0U;iF2812_BOOT_FLASH_WORDS)return 0; + for(i=0U;i<(sizeof(sectors)/sizeof(sectors[0])) && at=words; +} + +static int port_write(void *user, rsbt_u32_t offset, + const rsbt_byte_t *data, rsbt_u16_t length) +{ + rsbt_u16_t i=0U,word; unsigned long address; + (void)user; + if(offset+length>F2812_BOOT_APP_BYTES)return 0; + address=offset/2UL; + if(offset&1UL){ + word=flash_read_word(address);word=(word&0xFF00U)|(data[0]&0xFFU); + if(!flash_write_word(address,word))return 0;++address;++i; + } + while(iF2812_BOOT_APP_BYTES)return 0; + for(i=0U;i>8)&0xFFU);} + return 1; +} + +static int port_write_ram(void *user, rsbt_u32_t offset, + const rsbt_byte_t *data, rsbt_u16_t length) +{ + rsbt_u16_t i,word; volatile unsigned int *ram; + (void)user; + if(offset+length>F2812_BOOT_RAM_WORDS*2UL)return 0; + ram=(volatile unsigned int *)(F2812_BOOT_RAM_ADDRESS+offset/2UL); + if(offset&1UL){word=*ram;*ram++=(word&0xFF00U)|(data[0]&0xFFU);i=1U;}else i=0U; + while(i32U)n=32U; + if(!port_read(0,off,block,n))return 0; + for(i=0U;i>1)^((crc&1U)?0xEDB88320UL:0U);}} + return (crc^0xFFFFFFFFUL)==expected; +} + +void BalzamBoot_Init(void) +{ + rsbt_config_t c; rsbt_port_t p; + c.app_address=F2812_BOOT_APP_ADDRESS;c.app_size=F2812_BOOT_APP_BYTES;c.max_block=RSBT_MAX_BLOCK; + p.transmit=port_tx;p.erase=port_erase;p.write=port_write;p.read=port_read; + p.write_ram=port_write_ram;p.image_valid=port_valid;p.reboot=0; + init_flash();(void)rsbt_init(&boot,&c,&p,0); +} + +void BalzamBoot_FeedByte(unsigned int wire_byte){rsbt_feed(&boot,wire_byte&0xFFU);} +rsbt_state_t BalzamBoot_State(void){return boot.state;} diff --git a/c/rs485-boot/ports/tms320f2812/rs_boot_port_f2812.h b/c/rs485-boot/ports/tms320f2812/rs_boot_port_f2812.h new file mode 100644 index 0000000..c163e11 --- /dev/null +++ b/c/rs485-boot/ports/tms320f2812/rs_boot_port_f2812.h @@ -0,0 +1,17 @@ +#ifndef RS_BOOT_PORT_F2812_H +#define RS_BOOT_PORT_F2812_H + +#include "rs_boot_transport.h" + +/* External AM29-style flash is word-addressed by flash_tools.c. */ +#define F2812_BOOT_APP_ADDRESS 0x00100000UL +#define F2812_BOOT_FLASH_WORDS 0x00078000UL +#define F2812_BOOT_APP_BYTES (F2812_BOOT_FLASH_WORDS * 2UL) +#define F2812_BOOT_RAM_ADDRESS 0x00080000UL +#define F2812_BOOT_RAM_WORDS 0x00078000UL + +void BalzamBoot_Init(void); +void BalzamBoot_FeedByte(unsigned int wire_byte); +rsbt_state_t BalzamBoot_State(void); + +#endif diff --git a/c/rs485-boot/ports/tms320f28335/README.md b/c/rs485-boot/ports/tms320f28335/README.md new file mode 100644 index 0000000..a7e1654 --- /dev/null +++ b/c/rs485-boot/ports/tms320f28335/README.md @@ -0,0 +1,5 @@ +# TMS320F28335 +Uses `../c28x` to preserve 8-bit wire bytes on the 16-bit-byte C28x ABI. +Copy the config template, provide the board external-Flash functions and RS485 +direction macros. BEGIN byte 8 bit 0 enables Flash + RAM mirroring; Flash is +always retained and used for final CRC/recovery after reset. diff --git a/c/rs485-boot/ports/tms320f28335/rs_boot_port_config.template.h b/c/rs485-boot/ports/tms320f28335/rs_boot_port_config.template.h new file mode 100644 index 0000000..5de2e04 --- /dev/null +++ b/c/rs485-boot/ports/tms320f28335/rs_boot_port_config.template.h @@ -0,0 +1,17 @@ +#ifndef RS_BOOT_PORT_CONFIG_H +#define RS_BOOT_PORT_CONFIG_H +#include "DSP2833x_Device.h" +/* C28x addresses and sizes are in 16-bit words. */ +#define F28335_BOOT_FLASH_BASE 0x00100000UL +#define F28335_BOOT_FLASH_WORDS 0x00078000UL +#define F28335_BOOT_RAM_BASE 0x00080000UL +#define F28335_BOOT_RAM_WORDS 0x00078000UL +#define F28335_BOOT_USE_SCIB 0 +#define F28335_BOOT_RS485_TX() do { } while (0) +#define F28335_BOOT_RS485_RX() do { } while (0) +#define F28335_BOOT_REBOOT() do { } while (0) +/* Supply board Flash driver. word_offset is relative to FLASH_BASE. */ +int F28335_BOOT_FLASH_ERASE(unsigned long first_word,unsigned long word_count); +int F28335_BOOT_FLASH_PROGRAM(unsigned long word_offset,unsigned int value); +unsigned int F28335_BOOT_FLASH_READ(unsigned long word_offset); +#endif diff --git a/c/rs485-boot/ports/tms320f28335/rs_boot_port_f28335.c b/c/rs485-boot/ports/tms320f28335/rs_boot_port_f28335.c new file mode 100644 index 0000000..7fd39e2 --- /dev/null +++ b/c/rs485-boot/ports/tms320f28335/rs_boot_port_f28335.c @@ -0,0 +1,24 @@ +#include "rs_boot_port_config.h" +#include "rs_boot_port_f28335.h" +static rsbt_t boot; +static int tx(void*u,const rsbt_byte_t*d,rsbt_u16_t n){rsbt_u16_t i;(void)u;F28335_BOOT_RS485_TX();for(i=0U;iF28335_BOOT_FLASH_WORDS*2UL)return 0;return F28335_BOOT_FLASH_ERASE(0UL,(n+1UL)/2UL);} +static int wr(void*u,rsbt_u32_t o,const rsbt_byte_t*d,rsbt_u16_t n){rsbt_u16_t i=0U,w;unsigned long a=o/2UL;(void)u;if(o+n>F28335_BOOT_FLASH_WORDS*2UL)return 0;if(o&1UL){w=F28335_BOOT_FLASH_READ(a);w=(w&0xFF00U)|(d[0]&0xFFU);if(!F28335_BOOT_FLASH_PROGRAM(a++,w))return 0;i=1U;}while(iF28335_BOOT_FLASH_WORDS*2UL)return 0;for(i=0U;i>8);}return 1;} +static int ram(void*u,rsbt_u32_t o,const rsbt_byte_t*d,rsbt_u16_t n){rsbt_u16_t i=0U,w;volatile unsigned int*p;(void)u;if(o+n>F28335_BOOT_RAM_WORDS*2UL)return 0;p=(volatile unsigned int*)(F28335_BOOT_RAM_BASE+o/2UL);if(o&1UL){w=*p;*p++=(w&0xFF00U)|(d[0]&0xFFU);i=1U;}while(i32U)n=32U;if(!rd(0,o,b,n))return 0;for(i=0U;i>1)^((crc&1U)?0xEDB88320UL:0U);}}return(crc^0xFFFFFFFFUL)==expected;} +static void reboot(void*u){(void)u;F28335_BOOT_REBOOT();} +void F28335Boot_Init(void){rsbt_config_t c;rsbt_port_t p;c.app_address=F28335_BOOT_FLASH_BASE;c.app_size=F28335_BOOT_FLASH_WORDS*2UL;c.max_block=RSBT_MAX_BLOCK;p.transmit=tx;p.erase=erase;p.write=wr;p.read=rd;p.write_ram=ram;p.image_valid=valid;p.reboot=reboot;(void)rsbt_init(&boot,&c,&p,0);} +void F28335Boot_FeedByte(unsigned int b){rsbt_feed(&boot,b&0xFFU);}rsbt_state_t F28335Boot_State(void){return boot.state;} diff --git a/c/rs485-boot/ports/tms320f28335/rs_boot_port_f28335.h b/c/rs485-boot/ports/tms320f28335/rs_boot_port_f28335.h new file mode 100644 index 0000000..dd2c83b --- /dev/null +++ b/c/rs485-boot/ports/tms320f28335/rs_boot_port_f28335.h @@ -0,0 +1,7 @@ +#ifndef RS_BOOT_PORT_F28335_H +#define RS_BOOT_PORT_F28335_H +#include "rs_boot_transport.h" +void F28335Boot_Init(void); +void F28335Boot_FeedByte(unsigned int wire_byte); +rsbt_state_t F28335Boot_State(void); +#endif