RISC-V/minichlink/pgm-esp32s2-ch32xx.c
2025-02-05 15:55:13 +01:00

456 lines
10 KiB
C

#include <stdint.h>
#include "hidapi.c"
#include "minichlink.h"
struct ESP32ProgrammerStruct
{
void * internal;
hid_device * hd;
uint32_t state;
uint8_t commandbuffer[256];
int commandplace;
uint8_t reply[256];
int replylen;
int dev_version;
};
int ESPFlushLLCommands( void * dev );
static inline int SRemain( struct ESP32ProgrammerStruct * e )
{
return sizeof( e->commandbuffer ) - e->commandplace - 2; //Need room for EOF.
}
static inline void Write4LE( struct ESP32ProgrammerStruct * e, uint32_t val )
{
if( SRemain( e ) < 4 ) return;
uint8_t * d = e->commandbuffer + e->commandplace;
d[0] = val & 0xff;
d[1] = (val>>8) & 0xff;
d[2] = (val>>16) & 0xff;
d[3] = (val>>24) & 0xff;
e->commandplace += 4;
}
static inline void Write2LE( struct ESP32ProgrammerStruct * e, uint16_t val )
{
if( SRemain( e ) < 2 ) return;
uint8_t * d = e->commandbuffer + e->commandplace;
d[0] = val & 0xff;
d[1] = (val>>8) & 0xff;
e->commandplace += 2;
}
static inline void Write1( struct ESP32ProgrammerStruct * e, uint8_t val )
{
if( SRemain( e ) < 1 ) return;
uint8_t * d = e->commandbuffer + e->commandplace;
d[0] = val & 0xff;
e->commandplace ++;
}
static int ESPWriteReg32( void * dev, uint8_t reg_7_bit, uint32_t value )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
// printf( "WriteReg: %02x -> %08x\n", reg_7_bit, value );
if( SRemain( eps ) < 5 ) ESPFlushLLCommands( eps );
Write1( eps, (reg_7_bit<<1) | 1 );
Write4LE( eps, value );
return 0;
}
int ESPReadReg32( void * dev, uint8_t reg_7_bit, uint32_t * commandresp )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
ESPFlushLLCommands( eps );
Write1( eps, (reg_7_bit<<1) | 0 );
ESPFlushLLCommands( eps );
// printf( "ReadReg: %02x -> %d\n", reg_7_bit,eps->replylen );
if( eps->replylen < 6 )
{
return -9;
}
else
{
memcpy( commandresp, eps->reply+2, 4 );
return 0;
}
}
int ESPFlushLLCommands( void * dev )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
if( eps->commandplace >= sizeof( eps->commandbuffer ) )
{
fprintf( stderr, "Error: Command buffer overflow\n" );
return -5;
}
if( eps->commandplace == 1 ) return 0;
int r;
eps->commandbuffer[0] = 0xad; // Key report ID
eps->commandbuffer[eps->commandplace] = 0xff;
#if 0
int i;
for( i = 0; i < eps->commandplace; i++ )
{
if( ( i & 0xff ) == 0 ) printf( "\n" );
printf( "%02x ", eps->commandbuffer[i] );
}
printf("\n" );
#endif
r = hid_send_feature_report( eps->hd, eps->commandbuffer, 255 );
eps->commandplace = 1;
if( r < 0 )
{
fprintf( stderr, "Error: Got error %d when sending hid feature report.\n", r );
exit( -9 );
}
retry:
eps->reply[0] = 0xad; // Key report ID
r = hid_get_feature_report( eps->hd, eps->reply, sizeof( eps->reply ) );
/*
int i;
printf( "RESP: %d\n",eps->reply[0] );
for( i = 0; i < eps->reply[0]; i++ )
{
printf( "%02x ", eps->reply[i+1] );
if( (i % 16) == 15 ) printf( "\n" );
}
printf( "\n" );*/
if( eps->reply[0] == 0xff ) goto retry;
//printf( ">:::%d: %02x %02x %02x %02x %02x %02x\n", eps->replylen, eps->reply[0], eps->reply[1], eps->reply[2], eps->reply[3], eps->reply[4], eps->reply[5] );
if( r < 0 )
{
fprintf( stderr, "Error: Got error %d when sending hid feature report.\n", r );
return r;
}
eps->replylen = eps->reply[0] + 1; // Include the header byte.
return r;
}
int ESPControl3v3( void * dev, int bOn )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
if( SRemain( eps ) < 2 )
ESPFlushLLCommands( eps );
if( bOn )
Write2LE( eps, 0x03fe );
else
Write2LE( eps, 0x02fe );
return 0;
}
int ESPReadWord( void * dev, uint32_t address_to_read, uint32_t * data )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
//printf( "READ: %08x\n", address_to_read );
if( SRemain( eps ) < 6 )
ESPFlushLLCommands( eps );
Write2LE( eps, 0x09fe );
Write4LE( eps, address_to_read );
ESPFlushLLCommands( eps );
// printf( "Got: %d\n", eps->replylen );
if( eps->replylen < 5 )
{
return -9;
}
int tail = eps->replylen-5;
memcpy( data, eps->reply + tail + 1, 4 );
// printf( "Read Mem: %08x => %08x\n", address_to_read, *data );
return eps->reply[tail];
}
int ESPWriteWord( void * dev, uint32_t address_to_write, uint32_t data )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
//printf( "WRITE: %08x\n", address_to_write );
if( SRemain( eps ) < 10 )
ESPFlushLLCommands( eps );
Write2LE( eps, 0x08fe );
Write4LE( eps, address_to_write );
Write4LE( eps, data );
return 0;
}
static int ESPDelayUS( void * dev, int microseconds )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
if( SRemain( eps ) < 6 )
ESPFlushLLCommands( eps );
Write2LE( eps, 0x04fe );
Write2LE( eps, microseconds );
return 0;
}
static int ESPWaitForFlash( void * dev )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
if( SRemain( eps ) < 2 )
ESPFlushLLCommands( eps );
Write2LE( eps, 0x06fe );
return 0;
}
static int ESPWaitForDoneOp( void * dev, int ignore )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
if( SRemain( eps ) < 2 )
ESPFlushLLCommands( dev );
Write2LE( eps, 0x07fe );
return 0;
}
int ESPExit( void * dev )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
hid_close( eps->hd );
free( eps );
return 0;
}
int ESPBlockWrite64( void * dev, uint32_t address_to_write, uint8_t * data )
{
int writeretry = 0;
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
ESPFlushLLCommands( dev );
retry:
if( eps->dev_version >= 2 && InternalIsMemoryErased( (struct InternalState*)eps->internal, address_to_write ) )
Write2LE( eps, 0x0efe );
else
Write2LE( eps, 0x0bfe );
Write4LE( eps, address_to_write );
int i;
int timeout = 0;
for( i = 0; i < 64; i++ ) Write1( eps, data[i] );
InternalMarkMemoryNotErased( (struct InternalState*)eps->internal, address_to_write );
do
{
ESPFlushLLCommands( dev );
timeout++;
if( timeout > 1000 )
{
fprintf( stderr, "Error: Timed out block-writing 64\n" );
return -49;
}
} while( eps->replylen < 2 );
if( eps->reply[1] )
{
fprintf( stderr, "Error: Got code %d from ESP write algo. %d [%02x %02x %02x]\n", (char)eps->reply[1], eps->replylen, eps->reply[0], eps->reply[1], eps->reply[2] );
if( writeretry < 10 )
{
writeretry++;
goto retry;
}
}
return (char)eps->reply[1];
}
int ESPPerformSongAndDance( void * dev )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
Write2LE( eps, 0x01fe );
ESPFlushLLCommands( dev );
return 0;
}
int ESPVoidHighLevelState( void * dev )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
Write2LE( eps, 0x05fe );
ESPFlushLLCommands( dev );
DefaultVoidHighLevelState( dev );
return 0;
}
int ESPVendorCommand( void * dev, const char * cmd )
{
char command[10] = { 0 };
char tbuf[10] = { 0 };
int fields[10];
char c;
int i = 0;
int f = 0;
while( (c = *cmd++) )
{
if( c == ':' ) break;
if( c == '\0' ) break;
if( i + 1 >= sizeof( command )) break;
command[i++] = c;
command[i] = 0;
}
i = 0;
f = 0;
while( 1 )
{
c = *cmd++;
if( c == ':' || c == '\0' )
{
fields[f++] = SimpleReadNumberInt( tbuf, 0 );
puts( tbuf );
if( f == 10 ) break;
tbuf[0] = 0;
i = 0;
if( c == '\0' ) break;
continue;
}
if( i + 1 >= sizeof( tbuf )) break;
tbuf[i++] = c;
tbuf[i] = 0;
}
printf( "Got Vendor Command \"%s\"\n", command );
ESPFlushLLCommands( dev );
if( strcasecmp( command, "ECLK" ) == 0 )
{
printf( "Setting up external clock on pin.\n" );
if( f < 5 )
{
fprintf( stderr, "Error: Need fields :use_apll:sdm0:sdm1:sdm2:odiv try 1:0:0:8:3 for 24MHz\n" );
fprintf( stderr, "Definition:\n\
use_apll = Configures APLL = 480 / 4 = 120\n\
40 * (SDM2 + SDM1/(2^8) + SDM0/(2^16) + 4) / ( 2 * (ODIV+2) );\n\
Datasheet recommends that numerator is between 300 and 500MHz.\n ");
return -9;
}
Write2LE( dev, 0x0cfe );
Write1( dev, fields[0] );
Write1( dev, fields[1] );
Write1( dev, fields[2] );
Write1( dev, fields[3] );
Write1( dev, fields[4] );
Write1( dev, 0 );
Write1( dev, 0 );
Write1( dev, 0 );
ESPFlushLLCommands( dev );
}
else
{
fprintf( stderr, "Error: Unknown vendor command %s\n", command );
}
return 0;
}
int ESPPollTerminal( void * dev, uint8_t * buffer, int maxlen, uint32_t leaveflagA, int leaveflagB )
{
struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
ESPFlushLLCommands( dev );
Write1( dev, 0xfe );
Write1( dev, 0x0d );
Write4LE( dev, leaveflagA );
Write4LE( dev, leaveflagB );
Write1( dev, 0xff );
ESPFlushLLCommands( dev );
int rlen = eps->reply[0];
if( rlen < 1 ) return -8;
#if 0
int i;
printf( "RESP (ML %d): %d\n", maxlen,eps->reply[0] );
for( i = 0; i < eps->reply[0]; i++ )
{
printf( "%02x ", eps->reply[i+1] );
if( (i % 16) == 15 ) printf( "\n" );
}
printf( "\n" );
#endif
int errc = eps->reply[1];
if( errc > 7 ) return -7;
if( rlen - 1 >= maxlen ) return -6;
memcpy( buffer, eps->reply + 2, rlen - 1 );
return rlen - 1;
}
void * TryInit_ESP32S2CHFUN()
{
#define VID 0x303a
#define PID 0x4004
hid_init();
hid_device * hd = hid_open( VID, PID, L"s2-ch32xx-pgm-v0"); // third parameter is "serial"
if( !hd ) return 0;
struct ESP32ProgrammerStruct * eps = malloc( sizeof( struct ESP32ProgrammerStruct ) );
memset( eps, 0, sizeof( *eps ) );
eps->hd = hd;
eps->commandplace = 1;
eps->dev_version = 0;
memset( &MCF, 0, sizeof( MCF ) );
MCF.WriteReg32 = ESPWriteReg32;
MCF.ReadReg32 = ESPReadReg32;
MCF.FlushLLCommands = ESPFlushLLCommands;
MCF.DelayUS = ESPDelayUS;
MCF.Control3v3 = ESPControl3v3;
MCF.Exit = ESPExit;
MCF.VoidHighLevelState = ESPVoidHighLevelState;
MCF.PollTerminal = ESPPollTerminal;
// These are optional. Disabling these is a good mechanismto make sure the core functions still work.
MCF.WriteWord = ESPWriteWord;
MCF.ReadWord = ESPReadWord;
MCF.WaitForFlash = ESPWaitForFlash;
MCF.WaitForDoneOp = ESPWaitForDoneOp;
MCF.PerformSongAndDance = ESPPerformSongAndDance;
MCF.BlockWrite64 = ESPBlockWrite64;
MCF.VendorCommand = ESPVendorCommand;
// Reset internal programmer state.
Write2LE( eps, 0x0afe );
ESPFlushLLCommands( eps );
Write2LE( eps, 0xfefe );
ESPFlushLLCommands( eps );
if( eps->replylen > 1 )
{
eps->dev_version = eps->reply[1];
}
return eps;
}