Skip to content

Commit

Permalink
Initial version from Bogdan Marinescu.
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnyder committed Feb 15, 2010
0 parents commit 6b7422a
Show file tree
Hide file tree
Showing 7 changed files with 799 additions and 0 deletions.
147 changes: 147 additions & 0 deletions main.c
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;
}

41 changes: 41 additions & 0 deletions serial.h
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
184 changes: 184 additions & 0 deletions serial_posix.c
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;
}

Loading

0 comments on commit 6b7422a

Please sign in to comment.