feat(rs232): enable SCI-A FIFO on PM35 and preserve RS485

This commit is contained in:
2026-10-02 07:23:08 +03:00
parent 419d6b17dc
commit c6c9128238
8 changed files with 455 additions and 3 deletions
+118
View File
@@ -0,0 +1,118 @@
volatile struct SCI_REGS SciaRegs,ScibRegs;
struct { struct { struct { unsigned ACK9; } bit; } PIEACK; } PieCtrlRegs;
struct { struct { struct { unsigned GPIO34; } bit; } GPBDAT; } GpioDataRegs;
RS_DATA rs_a,rs_b;
unsigned int RS_Len[70],irq;
static unsigned int load_memory[4100];
static unsigned int __disable_interrupts(void) { unsigned old=irq;irq=1;return old; }
static void __restore_interrupts(unsigned state) { irq=state; }
void RS_SetLineMode(RS_DATA *p,int bits,char parity,int stop)
{ (void)p;(void)bits;(void)parity;(void)stop; }
static unsigned int queue[2][16],length[2],wire[2][20000],wire_count[2];
static unsigned int rx[2][16],rx_count[2],rx_pos[2],shift_pending[2],shift_checks;
static unsigned int port(RS_DATA *p) {return p->commnumber-1;}
static void model_interrupts(RS_DATA *p,unsigned tx)
{ p->SciRegs->SCICTL2.bit.TXINTENA=tx;p->SciRegs->SCICTL2.bit.RXBKINTENA=!tx; }
static void model_flush(RS_DATA *p)
{ unsigned i=port(p);rx_count[i]=rx_pos[i]=0;p->SciRegs->SCIFFRX.bit.RXFFST=0;p->SciRegs->SCIFFRX.bit.RXFFOVF=0; }
static unsigned int model_pop(RS_DATA *p)
{
unsigned i=port(p),v;assert(rx_pos[i]<rx_count[i]);v=rx[i][rx_pos[i]++];
p->SciRegs->SCIFFRX.bit.RXFFST=rx_count[i]-rx_pos[i];
p->SciRegs->SCIRXST.bit.RXRDY=rx_pos[i]<rx_count[i];return v;
}
static void model_push(RS_DATA *p,unsigned v)
{
unsigned i=port(p);assert(length[i]<16);queue[i][length[i]++]=v&255;
if(i==0)p->SciRegs->SCIFFTX.bit.TXFFST=length[i];
p->SciRegs->SCICTL2.bit.TXEMPTY=0;
}
static void model_shift(RS_DATA *p)
{
unsigned i=port(p);assert(length[i]==0);
if(i==0)assert(p->fifo_tx_active); /* last symbol cannot finish early */
shift_pending[i]=0;p->SciRegs->SCICTL2.bit.TXEMPTY=1;shift_checks++;
}
static void model_step(RS_DATA *p)
{
unsigned i=port(p),j;
if(length[i]) {
wire[i][wire_count[i]++]=queue[i][0];
for(j=1;j<length[i];j++)queue[i][j-1]=queue[i][j];
length[i]--;shift_pending[i]=1;
if(i==0)p->SciRegs->SCIFFTX.bit.TXFFST=length[i];
} else if(shift_pending[i]) model_shift(p);
if(i==0 && p->SciRegs->SCIFFTX.bit.TXFFIENA &&
length[i]<=p->SciRegs->SCIFFTX.bit.TXFFIL) RS_TX_Handler(p);
}
static void reset(void)
{
memset(&rs_a,0,sizeof(rs_a));memset(&rs_b,0,sizeof(rs_b));
memset((void *)&SciaRegs,0,sizeof(SciaRegs));memset((void *)&ScibRegs,0,sizeof(ScibRegs));
memset(length,0,sizeof(length));memset(wire_count,0,sizeof(wire_count));
memset(rx_count,0,sizeof(rx_count));memset(rx_pos,0,sizeof(rx_pos));
memset(shift_pending,0,sizeof(shift_pending));
rs_a.commnumber=1;rs_b.commnumber=2;rs_a.SciRegs=&SciaRegs;rs_b.SciRegs=&ScibRegs;
SciaRegs.SCICTL2.bit.TXEMPTY=ScibRegs.SCICTL2.bit.TXEMPTY=1;
rs_a.RS_Flag9bit=rs_b.RS_Flag9bit=1;
RS_Len[3]=8;RS_Len[6]=8;RS_Len[16]=13;RS_Len[51]=12;
GpioDataRegs.GPBDAT.bit.GPIO34=1;irq=0;
}
static void feed(RS_DATA *p,const unsigned *bytes,unsigned n)
{
unsigned i=port(p),j;assert(n<=16);rx_pos[i]=0;rx_count[i]=n;
for(j=0;j<n;j++)rx[i][j]=bytes[j];
p->SciRegs->SCIFFRX.bit.RXFFST=n;p->SciRegs->SCIRXST.bit.RXRDY=n!=0;
RS_RX_Handler(p);
}
/* HANDLERS */
int main(void)
{
unsigned data[4200],sizes[]={0,1,2,7,8,15,16,17,31,120,253,400,8194};
unsigned a,n,i,mode;unsigned request[]={16,3,0x10,0,0,16,0,0};
for(mode=0;mode<2;mode++)for(a=0;a<sizeof(sizes)/sizeof(sizes[0]);a++) {
reset();n=sizes[a];for(i=0;i<4200;i++)data[i]=(i*131U+17U)&65535;
if(mode==0 && n>4200)continue;
assert((mode ? RS_BSend(&rs_a,data,n):RS_Send(&rs_a,data,n))==0);
if(n && rs_a.fifo_tx_active)assert(rs_a.RS_Flag9bit==0);
RS_FifoWait(&rs_a);assert(!rs_a.fifo_tx_active && wire_count[0]==n);
for(i=0;i<n;i++)assert(wire[0][i]==(mode?((i&1)?LOBYTE(data[i/2]):HIBYTE(data[i/2])):LOBYTE(data[i])));
assert(GpioDataRegs.GPBDAT.bit.GPIO34==1); /* RS232 never touches DE */
assert(!irq);
}
assert(shift_checks>0);
reset();feed(&rs_a,request,8);assert(rs_a.RS_DataReady && rs_a.RS_HeaderCnt==8);
reset();feed(&rs_a,request,3);feed(&rs_a,request+3,5);assert(rs_a.RS_DataReady);
/* LOAD payload, including a short final chunk: nothing waits for byte 8. */
reset();rs_a.RS_PrevCmd=CMD_INITLOAD;rs_a.RS_Length=8194;
rs_a.pRS_RecvPtr=rs_a.pRecvPtr=load_memory;
data[0]=16;data[1]=CMD_LOAD;feed(&rs_a,data,2);
for(a=0;a<8194;a+=n) {
n=8194-a;n=n<16?n:16;
for(i=0;i<n;i++)data[i]=(a+i)&255;
feed(&rs_a,data,n);
}
assert(rs_a.RS_DataReady && rs_a.RS_RecvLen==8194);
for(i=0;i<4097;i++)assert(load_memory[i]==(((2*i)&255)<<8 | ((2*i+1)&255)));
reset();data[0]=1;data[1]=2;RS_Send(&rs_a,data,2);
feed(&rs_b,request,8);assert(rs_b.RS_DataReady && rs_a.fifo_tx_active);
RS_FifoWait(&rs_a);
reset();request[3]=0xC000;feed(&rs_a,request,8);
assert(!rs_a.RS_DataReady && rs_a.fifo_rx_errors==1 && rs_a.fifo_rx_guard);
request[3]=0;feed(&rs_a,request,8);assert(!rs_a.RS_DataReady);
for(i=0;i<4;i++)RS_FifoTick1ms();
feed(&rs_a,request,8);assert(rs_a.RS_DataReady);
reset();SciaRegs.SCIFFRX.bit.RXFFOVF=1;RS_RX_Handler(&rs_a);
assert(rs_a.fifo_overflows==1 && !rs_a.BS_LoadOK);
for(i=0;i<4;i++)RS_FifoTick1ms();feed(&rs_a,request,8);assert(rs_a.RS_DataReady);
/* A spurious old threshold interrupt may not finish an occupied FIFO. */
reset();RS_Send(&rs_a,data,8);RS_TX_Handler(&rs_a);assert(rs_a.fifo_tx_active);
RS_FifoWait(&rs_a);assert(wire_count[0]==8);
/* SCI-B keeps the original RX parser and IRQ/TX path, never FIFO state. */
reset();feed(&rs_b,request,8);assert(rs_b.RS_DataReady);
reset();RS_Send(&rs_b,data,2);assert(!rs_b.fifo_tx_active && length[1]==1);
model_step(&rs_b);RS_TX_Handler(&rs_b); /* legacy RS_Wait drains final char */
assert(GpioDataRegs.GPBDAT.bit.GPIO34==1);
puts("PM35 RS232 FIFO: PASS (TX/RX/errors/recovery/SCI-B isolation)");return 0;
}
+73
View File
@@ -0,0 +1,73 @@
"""Exercise production RS485.c functions with FIFO register side effects."""
import argparse
import os
from pathlib import Path
import re
import subprocess
import tempfile
root=Path(__file__).resolve().parents[2]
def read(path):
return re.sub(r'/\*.*?\*/|//[^\n]*','',path.read_bytes().decode('cp1251').replace('\r\n','\n'),flags=re.S)
source=read(root/'Source/Internal/RS485.c')
names=['RS_RX_Handler','RS_TX_Handler','RS_Send','RS_BSend','RS_SetBitMode',
'RS_FifoWait','RS_FifoTx','RS_FifoStart','RS_FifoAbort','RS_FifoTick1ms']
prototypes=[];functions=[]
for name in names:
match=re.search(r'(?:static\s+)?(?:void|int)\s+'+name+r'\([^;{}]*\)\s*\{',source)
assert match,name
begin=source.index('{',match.start());end=begin+1;depth=1
while depth:
depth+=(source[end]=='{')-(source[end]=='}');end+=1
prototypes.append(source[match.start():begin]+';')
functions.append(source[match.start():end])
body='\n'.join(functions)
# TI C28x char is 16 bits: 0x80..0xFF remain positive before word packing.
body=re.sub(r'\bchar\s+Rc;', 'unsigned int Rc;', body)
body=body.replace('received=rs_arr->SciRegs->SCIRXBUF.all;', 'received=model_pop(rs_arr);')
body=body.replace('Rc = rs_arr->SciRegs->SCIRXBUF.bit.RXDT;', 'Rc=model_pop(rs_arr);')
body=body.replace('rs_arr->SciRegs->SCIFFRX.bit.RXFIFORESET=0;',
'model_flush(rs_arr);rs_arr->SciRegs->SCIFFRX.bit.RXFIFORESET=0;')
body=body.replace('rs_arr->SciRegs->SCICTL1.bit.SWRESET=1;',
'rs_arr->SciRegs->SCIRXST.all=0;rs_arr->SciRegs->SCICTL1.bit.SWRESET=1;')
body=body.replace('while (!rs_arr->SciRegs->SCICTL2.bit.TXEMPTY) { }',
'while (!rs_arr->SciRegs->SCICTL2.bit.TXEMPTY) { model_step(rs_arr); }',1)
body=body.replace('while (!rs_arr->SciRegs->SCICTL2.bit.TXEMPTY) { }',
'while (!rs_arr->SciRegs->SCICTL2.bit.TXEMPTY) { model_shift(rs_arr); }')
body=body.replace('!rs_arr->SciRegs->SCICTL2.bit.TXEMPTY) { }',
'!rs_arr->SciRegs->SCICTL2.bit.TXEMPTY) { model_step(rs_arr); }')
header=read(root/'Source/Internal/Include/RS485.h')
header=re.sub(r'#define SCI_send\(x,y\)[^\n]*', '#define SCI_send(x,y) model_push(x,y)',header)
header=re.sub(r'#define enableUARTInt\(x\)[^\n]*', '#define enableUARTInt(x) model_interrupts(x,0)',header)
header=re.sub(r'#define enableUARTIntW\(x\)[^\n]*', '#define enableUARTIntW(x) model_interrupts(x,1)',header)
header=re.sub(r'#define Rec_Bloc_Begin[^\n]*', '#define Rec_Bloc_Begin ((uintptr_t)load_memory)',header)
header=re.sub(r'#define Rec_Bloc_End[^\n]*', '#define Rec_Bloc_End ((uintptr_t)(load_memory+4100))',header)
registers=read(root/'Source/External/v120/DSP2833x_headers/include/DSP2833x_Sci.h')
defines='''
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
typedef unsigned short Uint16;
#define interrupt
#define true 1
#define false 0
#define BM_CHAR32 0
#define BM_PACKED 1
#define CNTRL_ADDR_UNIVERSAL 16
#define CNTRL_ADDR 5
#define ADDR_FOR_ALL 0
#define LOBYTE(x) ((x)&255)
#define HIBYTE(x) (((x)>>8)&255)
enum {CMD_MODBUS_3=3,ANS_MODBUS_4=4,CMD_MODBUS_6=6,CMD_MODBUS_16=16,
CMD_LOAD=51,CMD_INITLOAD=58,CMD_STD_ANS=66};
'''
harness=(Path(__file__).with_name('model.inc')).read_text()
before,after=harness.split('/* HANDLERS */')
parser=argparse.ArgumentParser();parser.add_argument('--cc',required=True);args=parser.parse_args()
env=dict(os.environ);env['PATH']=str(Path(args.cc).parent)+os.pathsep+env.get('PATH','')
with tempfile.TemporaryDirectory(prefix='pm35-fifo-') as directory:
path=Path(directory);c=path/'model.c';exe=path/'model.exe'
c.write_text(defines+registers+header+'\n'.join(prototypes)+before+body+after)
subprocess.run([args.cc,'-std=c99','-O1','-Werror=implicit-function-declaration',str(c),'-o',str(exe)],check=True,env=env)
subprocess.run([str(exe)],check=True,env=env,timeout=20)