-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial version from Bogdan Marinescu.
- Loading branch information
0 parents
commit 6b7422a
Showing
7 changed files
with
799 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// Loader driver | ||
|
||
#include "stm32ld.h" | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <errno.h> | ||
#include <limits.h> | ||
|
||
static FILE *fp; | ||
static u32 fpsize; | ||
|
||
#define BL_VERSION_MAJOR 2 | ||
#define BL_VERSION_MINOR 1 | ||
#define CHIP_ID 0x0414 | ||
|
||
// **************************************************************************** | ||
// Helper functions and macros | ||
|
||
// Get data function | ||
static u32 writeh_read_data( u8 *dst, u32 len ) | ||
{ | ||
size_t readbytes = 0; | ||
|
||
if( !feof( fp ) ) | ||
readbytes = fread( dst, 1, len, fp ); | ||
return ( u32 )readbytes; | ||
} | ||
|
||
// Progress function | ||
static void writeh_progress( u32 wrote ) | ||
{ | ||
unsigned pwrite = ( wrote * 100 ) / fpsize; | ||
static int expected_next = 10; | ||
|
||
if( pwrite >= expected_next ) | ||
{ | ||
printf( "%d%% ", expected_next ); | ||
expected_next += 10; | ||
} | ||
} | ||
|
||
// **************************************************************************** | ||
// Entry point | ||
|
||
int main( int argc, const char **argv ) | ||
{ | ||
u8 minor, major; | ||
u16 version; | ||
long baud; | ||
|
||
// Argument validation | ||
if( argc != 4 ) | ||
{ | ||
fprintf( stderr, "Usage: stm32ld <port> <baud> <binary image name>\n" ); | ||
exit( 1 ); | ||
} | ||
errno = 0; | ||
baud = strtol( argv[ 2 ], NULL, 10 ); | ||
if( ( errno == ERANGE && ( baud == LONG_MAX || baud == LONG_MIN ) ) || ( errno != 0 && baud == 0 ) || ( baud < 0 ) ) | ||
{ | ||
fprintf( stderr, "Invalid baud '%s'\n", argv[ 2 ] ); | ||
exit( 1 ); | ||
} | ||
if( ( fp = fopen( argv[ 3 ], "rb" ) ) == NULL ) | ||
{ | ||
fprintf( stderr, "Unable to open %s\n", argv[ 3 ] ); | ||
exit( 1 ); | ||
} | ||
else | ||
{ | ||
fseek( fp, 0, SEEK_END ); | ||
fpsize = ftell( fp ); | ||
fseek( fp, 0, SEEK_SET ); | ||
} | ||
|
||
// Connect to bootloader | ||
if( stm32_init( argv[ 1 ], baud ) != STM32_OK ) | ||
{ | ||
fprintf( stderr, "Unable to connect to bootloader\n" ); | ||
exit( 1 ); | ||
} | ||
|
||
// Get version | ||
if( stm32_get_version( &major, &minor ) != STM32_OK ) | ||
{ | ||
fprintf( stderr, "Unable to get bootloader version\n" ); | ||
exit( 1 ); | ||
} | ||
else | ||
{ | ||
printf( "Found bootloader version: %d.%d\n", major, minor ); | ||
if( major != BL_VERSION_MAJOR || minor != BL_VERSION_MINOR ) | ||
{ | ||
fprintf( stderr, "Unsupported bootloader version" ); | ||
exit( 1 ); | ||
} | ||
} | ||
|
||
// Get chip ID | ||
if( stm32_get_chip_id( &version ) != STM32_OK ) | ||
{ | ||
fprintf( stderr, "Unable to get chip ID\n" ); | ||
exit( 1 ); | ||
} | ||
else | ||
{ | ||
printf( "Chip ID: %04X\n", version ); | ||
if( version != CHIP_ID ) | ||
{ | ||
fprintf( stderr, "Unsupported chip ID" ); | ||
exit( 1 ); | ||
} | ||
} | ||
|
||
// Write unprotect | ||
if( stm32_write_unprotect() != STM32_OK ) | ||
{ | ||
fprintf( stderr, "Unable to execute write unprotect\n" ); | ||
exit( 1 ); | ||
} | ||
else | ||
printf( "Cleared write protection.\n" ); | ||
|
||
// Erase flash | ||
if( stm32_erase_flash() != STM32_OK ) | ||
{ | ||
fprintf( stderr, "Unable to erase chip\n" ); | ||
exit( 1 ); | ||
} | ||
else | ||
printf( "Erased FLASH memory.\n" ); | ||
|
||
// Program flash | ||
setbuf( stdout, NULL ); | ||
printf( "Programming flash ... "); | ||
if( stm32_write_flash( writeh_read_data, writeh_progress ) != STM32_OK ) | ||
{ | ||
fprintf( stderr, "Uanble to program FLASH memory.\n" ); | ||
exit( 1 ); | ||
} | ||
else | ||
printf( "\nDone.\n" ); | ||
|
||
fclose( fp ); | ||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// STM32 loader serial interface | ||
|
||
#ifndef __SERIAL_H__ | ||
#define __SERIAL_H__ | ||
|
||
#include "type.h" | ||
|
||
#define SER_INF_TIMEOUT 0xFFFFFFFF | ||
#define SER_NO_TIMEOUT 0 | ||
#define SER_OK 0 | ||
#define SER_ERR 1 | ||
|
||
// Serial interface modes (blocking or non blocking) | ||
#define SER_MODE_BLOCKING 0 | ||
#define SER_MODE_NONBLOCKING 1 | ||
|
||
// Setup constants | ||
#define SER_PARITY_NONE 0 | ||
#define SER_PARITY_EVEN 1 | ||
#define SER_PARITY_ODD 2 | ||
|
||
#define SER_STOPBITS_1 0 | ||
#define SER_STOPBITS_1_5 1 | ||
#define SER_STOPBITS_2 2 | ||
|
||
#define SER_DATABITS_5 5 | ||
#define SER_DATABITS_6 6 | ||
#define SER_DATABITS_7 7 | ||
#define SER_DATABITS_8 8 | ||
|
||
// Serial access functions (to be implemented by each platform) | ||
ser_handler ser_open( const char *sername ); | ||
void ser_close( ser_handler id ); | ||
int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits ); | ||
u32 ser_read( ser_handler id, u8* dest, u32 maxsize ); | ||
int ser_read_byte( ser_handler id ); | ||
u32 ser_write( ser_handler id, const u8 *src, u32 size ); | ||
u32 ser_write_byte( ser_handler id, u8 data ); | ||
void ser_set_timeout_ms( ser_handler id, u32 timeout ); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
// Serial inteface implementation for POSIX-compliant systems | ||
|
||
#include "serial.h" | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
#include <fcntl.h> | ||
#include <errno.h> | ||
#include <termios.h> | ||
#include <sys/select.h> | ||
#include <sys/time.h> | ||
#include <sys/types.h> | ||
|
||
static u32 ser_timeout = SER_INF_TIMEOUT; | ||
|
||
// Open the serial port | ||
ser_handler ser_open( const char* sername ) | ||
{ | ||
int fd; | ||
|
||
if( ( fd = open( sername, O_RDWR | O_NOCTTY | O_NDELAY ) ) == -1 ) | ||
perror( "ser_open: unable to open port" ); | ||
else | ||
fcntl( fd, F_SETFL, 0 ); | ||
return ( ser_handler )fd; | ||
} | ||
|
||
// Close the serial port | ||
void ser_close( ser_handler id ) | ||
{ | ||
close( ( int )id ); | ||
} | ||
|
||
// Helper function: get baud ID from actual baud rate | ||
#define BAUDCASE(x) case x: return B##x | ||
static u32 ser_baud_to_id( u32 baud ) | ||
{ | ||
switch( baud ) | ||
{ | ||
BAUDCASE( 1200 ); | ||
BAUDCASE( 1800 ); | ||
BAUDCASE( 2400 ); | ||
BAUDCASE( 4800 ); | ||
BAUDCASE( 9600 ); | ||
BAUDCASE( 19200 ); | ||
BAUDCASE( 38400 ); | ||
BAUDCASE( 57600 ); | ||
BAUDCASE( 115200 ); | ||
BAUDCASE( 230400 ); | ||
} | ||
return 0; | ||
} | ||
|
||
// Helper function: get number of bits ID from actual number of bits | ||
#define NBCASE(x) case x: return CS##x | ||
static int ser_number_of_bits_to_id( int nb ) | ||
{ | ||
switch( nb ) | ||
{ | ||
NBCASE( 5 ); | ||
NBCASE( 6 ); | ||
NBCASE( 7 ); | ||
NBCASE( 8 ); | ||
} | ||
return 0; | ||
} | ||
|
||
int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits ) | ||
{ | ||
struct termios termdata; | ||
int hnd = ( int )id; | ||
|
||
usleep( 200000 ); | ||
tcgetattr( hnd, &termdata ); | ||
|
||
// Baud rate | ||
cfsetispeed( &termdata, ser_baud_to_id( baud ) ); | ||
cfsetospeed( &termdata, ser_baud_to_id( baud ) ); | ||
|
||
// Parity / stop bits | ||
termdata.c_cflag &= ~CSTOPB; | ||
if( parity == SER_PARITY_NONE ) // no parity | ||
{ | ||
termdata.c_cflag &= ~PARENB; | ||
} | ||
else if( parity == SER_PARITY_EVEN ) // even parity | ||
{ | ||
termdata.c_cflag |= PARENB; | ||
termdata.c_cflag &= ~PARODD; | ||
} | ||
else if( parity == SER_PARITY_ODD ) // odd parity | ||
{ | ||
termdata.c_cflag |= PARENB; | ||
termdata.c_cflag |= PARODD; | ||
} | ||
|
||
// Data bits | ||
termdata.c_cflag |= ( CLOCAL | CREAD ); | ||
termdata.c_cflag &= ~CSIZE; | ||
termdata.c_cflag |= ser_number_of_bits_to_id( databits ); | ||
|
||
// Disable HW and SW flow control | ||
termdata.c_cflag &= ~CRTSCTS; | ||
termdata.c_iflag &= ~( IXON | IXOFF | IXANY ); | ||
|
||
// Raw input | ||
termdata.c_lflag &= ~( ICANON | ECHO | ECHOE | ISIG ); | ||
|
||
// Raw output | ||
termdata.c_oflag &= ~OPOST; | ||
|
||
// Check and strip parity bit | ||
if( parity == SER_PARITY_NONE ) | ||
termdata.c_iflag &= ~( INPCK | ISTRIP ); | ||
else | ||
termdata.c_iflag |= ( INPCK | ISTRIP ); | ||
|
||
// Setup timeouts | ||
termdata.c_cc[ VMIN ] = 1; | ||
termdata.c_cc[ VTIME ] = 0; | ||
|
||
// Set the attibutes now | ||
tcsetattr( hnd, TCSANOW, &termdata ); | ||
|
||
// Flush everything | ||
tcflush( hnd, TCIOFLUSH ); | ||
|
||
// And set blocking mode by default | ||
fcntl( id, F_SETFL, 0 ); | ||
} | ||
|
||
// Read up to the specified number of bytes, return bytes actually read | ||
u32 ser_read( ser_handler id, u8* dest, u32 maxsize ) | ||
{ | ||
if( ser_timeout == SER_INF_TIMEOUT ) | ||
return ( u32 )read( ( int )id, dest, maxsize ); | ||
else | ||
{ | ||
fd_set readfs; | ||
struct timeval tv; | ||
int retval; | ||
|
||
FD_ZERO( &readfs ); | ||
FD_SET( ( int )id, &readfs ); | ||
tv.tv_sec = ser_timeout / 1000000; | ||
tv.tv_usec = ( ser_timeout % 1000000 ) * 1000; | ||
retval = select( ( int )id + 1, &readfs, NULL, NULL, &tv ); | ||
if( retval == -1 || retval == 0 ) | ||
return 0; | ||
else | ||
return ( u32 )read( ( int )id, dest, maxsize ); | ||
} | ||
} | ||
|
||
// Read a single byte and return it (or -1 for error) | ||
int ser_read_byte( ser_handler id ) | ||
{ | ||
u8 data; | ||
int res = ser_read( id, &data, 1 ); | ||
|
||
return res == 1 ? data : -1; | ||
} | ||
|
||
// Write up to the specified number of bytes, return bytes actually written | ||
u32 ser_write( ser_handler id, const u8 *src, u32 size ) | ||
{ | ||
u32 res; | ||
|
||
res = ( u32 )write( ( int )id, src, size ); | ||
return res; | ||
} | ||
|
||
// Write a byte to the serial port | ||
u32 ser_write_byte( ser_handler id, u8 data ) | ||
{ | ||
return ( u32 )write( id, &data, 1 ); | ||
} | ||
|
||
// Set communication timeout | ||
void ser_set_timeout_ms( ser_handler id, u32 timeout ) | ||
{ | ||
ser_timeout = timeout; | ||
} | ||
|
Oops, something went wrong.