On Jun 17, 2005, at 4:53 AM, Dale Cunningham wrote:

I'm trying to write a bootstrap routine in C that will reside in flash and be copied to RAM for execution. Can anyone give me some helpful hints on how to do that?

I've searched the docs for any reference to relocatable code (there will be some subroutines, also in RAM) or preprocessor commands that might be able to specify that this code will be running at a particular address (in this case within the RAM) and haven't been able to find anything that relates to this problem.


I have devised a way to do this for assembly routines. The data and code will be copied to the stack and run from there. The code is in C, but the routine you want to put in the stack must be in assembly for the moment. I have also got some misc routines in there, including buffered SD16 with timestamps, buffered UART in assembly and other stuff. The important routine is WriteBlock() in asmlib.s. It shows how to copy a routine to stack and run it from there. In this case, it is used to write to info memory. I have included the necessary files that should form a good example.

The configuration of this code is in an MSP430F427 with 32.768k XTAL and a multiplexer on analog A2. The selection signal is P2.2.

This whole code is the stuff I want to contribute to the example library of MSPGCC. At the moment, it is not quite "pretty" enough, but I will soon butcher it to parts to form a complete example. The entire code is well commented though.

If any of this code is used, please credit Tennessee Carmel-Veilleux (veill...@tentech.ca)

Best Regards,

Tennessee Carmel-Veilleux
/*******************************************************************************
* Name:        asmlib.h                                                        *
* Author:      Tennessee Carmel-Veilleux                                       *
* Created:     05/07/2005                                                      *
* Module:      USBVoltAmp ASM library declarations                             *
* Version:     1.1                                                             *
* Copyright:   (C)2005 Tennessee Carmel-Veilleux                               *
* Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut     *
* utiliser ce code ainsi que tous les fichiers et composants dérivés pour      *
* n'importe quel usage qui lui soit utile.                                     *
*                                                                              *
* Version history:                                                             *
* - 1.0 (05/07/2005): Initial release                                          *
* - 1.1 (06/04/2005): All basic functions implemented                          *
*******************************************************************************/

#ifndef ASMLIB_H
#define ASMLIB_H

#include "hardware.h"

// Buffered UART buffers
extern volatile unsigned char RxQueue[RX_QUEUE_SIZE];
extern volatile unsigned char TxQueue[TX_QUEUE_SIZE];
extern volatile unsigned char RxSize, RxHead, RxTail;
extern volatile unsigned char TxSize, TxHead, TxTail;

// SD16 buffers and flags
extern volatile unsigned short SD16Results[4];
extern volatile unsigned long SD16Timestamps[4];
extern volatile unsigned char SD16Flags;

//Function prototypes for the functions in asmlib.S

// NO NEED for putchar SINCE IT IS ALREADY DEFINED IN stdio.h
// int putchar(int c);
int getch();
void WriteBlock(unsigned char *addr);
unsigned long int GetIntervalClock(void);

#endif //ASMLIB_H

Attachment: ASMLIB.S
Description: Binary data

/*******************************************************************************
* Name:        fonctions.c                                                     *
* Author:      Tennessee Carmel-Veilleux                                       *
* Created:     05/07/2005                                                      *
* Module:      USBVoltAmp parser callback functions                            *
* Version:     1.1                                                             *
* Copyright:   (C)2005 Tennessee Carmel-Veilleux                               *
* Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut     *
* utiliser ce code ainsi que tous les fichiers et composants dérivés pour      *
* n'importe quel usage qui lui soit utile.                                     *
*                                                                              *
* Version history:                                                             *
* - 1.0 (05/07/2005): Initial release                                          *
* - 1.1 (06/04/2005): All basic functions implemented                          *
*******************************************************************************/
#include "main.h"
#include <stdio.h>
#include <string.h>

#define putc(c) putchar(c)

uint8 EEbuf[128]; // Buffer d'EEPROM (info flash)

void RMEM(void) {
    uint8 d;
    uint16 a;

    // Lecture du contenu de la mémoire info (0x1000 à 0x107F) dans le buffer
    for(a = 0x1000; a < 0x1080; a++) {
        EEbuf[a-0x1000] = *((uint8 *)(a));
    }
    
    // Lecture de l'octet désiré
    a = (uint8)parametre[0];
    d = EEbuf[a];
    
    printf("%u\r",d);   // Transmission de l'octet
    if (debug) putc('\n');
}

//-----------------------------------------------------------------------
//  WMEM_x_d<lf><cr>
//
//  Fonction Orphy émulée
//  Écriture dans l'EEPROM d'un octet. L'écriture se fait seulement
//  lorsque ZAPPLY appellée (deux blocs de 64 octets s'écriront).
//  Avant le premier WMEM après un PowerUp ou un ZAPPLY, on doit faire
//  un ZRMEM dummy pour lire le buffer de l'EEPROM
//-----------------------------------------------------------------------

void WMEM(void) {
    uint8 d, a;
    
    // Obtention de la donnée et de l'adresse
    a = (uint8)parametre[0];
    d = (uint8)parametre[1];

    EEbuf[a] = d; // Écriture dans le buffer
    
    printf("%u\r",d);   // Transmission de l'octet
    if (debug) putc('\n');
}

//-----------------------------------------------------------------------
//  APPLY<lf><cr>
//
//  Écriture dans l'EEPROM du bloc EEbuf à partir d'une fonction en
//  assembleur. Voir WMEM().
//-----------------------------------------------------------------------

void APPLY(void) {
    WriteBlock(EEbuf);
    putc(ACK_CHAR);
    putc('\r');
}

// Parametre 0: data format (0: DEC, 1:HEX)
void DUMP(void) {
    uint16 i;
    
    if (debug) 
        printf("Affichage à partir de $1000 + 0\n\r");
    else {
        if (parametre[0]) {
            printf("*0000\r");
        } else {
            printf("*0\r");
        }
    }
    
    for (i = 0; i < 128; i++) {
        if (parametre[0]) {
            printf("%02X",EEbuf[i]);
        } else {
            printf("%u",EEbuf[i]);
        }
        if (debug)
            putc(' ');
        else
            putc('\r');
    }
}

/*******************************************************************************
* Name:        hardware.h                                                      *
* Author:      Tennessee Carmel-Veilleux                                       *
* Created:     05/07/2005                                                      *
* Module:      USBVoltAmp hardware constants                                   *
* Version:     1.1                                                             *
* Copyright:   (C)2005 Tennessee Carmel-Veilleux                               *
* Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut     *
* utiliser ce code ainsi que tous les fichiers et composants dérivés pour      *
* n'importe quel usage qui lui soit utile.                                     *
*                                                                              *
* Version history:                                                             *
* - 1.0 (05/07/2005): Initial release                                          *
* - 1.1 (06/04/2005): All basic functions implemented                          *
*******************************************************************************/


#ifndef HARDWARE_H
#define HARDWARE_H

#define __MSP430_427__

#include <io.h>
#include <signal.h>
#include <iomacros.h>

#define FALSE 0
#define TRUE 1
#define NULL 0

//#define SMCLK (1048576ul)
#define SMCLK (2097152ul)
#define HOST_BAUD (115200ul)

#define LED0            0x01 // LED0 is on P2.0
#define SW0             0x02 // SW0 is on P2.1
#define CHAN_SEL        0x04 // SEL is on P2.2

//Port Output Register 'P1OUT, P2OUT':
#define P1OUT_INIT      0                       // Init Output data of port1
#define P2OUT_INIT      0                       // Init Output data of port2

//Port Direction Register 'P1DIR, P2DIR':
#define P1DIR_INIT      0xff                    // Init of Port1 Data-Direction 
Reg (Out=1 / Inp=0)
#define P2DIR_INIT      0x15                    // Init of Port2 Data-Direction 
Reg (Out=1 / Inp=0)

//Selection of Port or Module -Function on the Pins 'P1SEL, P2SEL'
#define P1SEL_INIT      0x22                       // P1-Modules:
#define P2SEL_INIT      0x30                       // P2-Modules:

//Interrupt capabilities of P1 and P2
#define P1IE_INIT       0                       // Interrupt Enable (0=dis 
1=enabled)
#define P2IE_INIT       0                       // Interrupt Enable (0=dis 
1=enabled)
#define P1IES_INIT      0                       // Interrupt Edge Select (0=pos 
1=neg)
#define P2IES_INIT      0                       // Interrupt Edge Select (0=pos 
1=neg)

// WDT in interval mode for RTC (ACLK / 32768 interrupt rate)
#define WDTCTL_INIT     (WDTPW | WDTTMSEL | WDTCNTCL | WDTSSEL)

// TimerA in continuous up mode, interrupt on overflow, clear on init, Clk = 
(ACLK / 8) (4096 Hz)
#define TACTL_INIT      (TASSEL0 | MC1 | ID1 | ID0 | TAIE)

#define ACK_CHAR '^'

/* UART queue constants */
#define RX_QUEUE_SIZE 32
#define TX_QUEUE_SIZE 16

/* SD16 init values for 1048581 Hz */
#define SD16CTL_INIT (SD16DIV0 | SD16SSEL1 ) // External reference, ACLK / 2 
clock (16384 Hz)
#define SD16CCTL0_INIT (SD16IE | SD16GRP) // CH0 Interrupt enabled, group 
operation, 256:1, 16 MSB, continuous, offset binary 
#define SD16CCTL1_INIT (SD16IE ) // CH1 Interrupt enabled, master of CH0, 
256:1, 16 MSB, continuous, offset binary
#define SD16CCTL2_INIT (SD16IE | SD16OSR0) // CH2 Interrupt enabled, 128:1, 16 
MSB, continuous, offset binary
#define SD16INCTL0_INIT 0x00 // CH0 on A0
#define SD16INCTL1_INIT 0x01 // CH1 on A1
#define SD16INCTL2_INIT (0x02) // CH2 on A2 --- SHORT ON A2

/* SD16Flags values */
#define CH0_F 0x01
#define CH1_F 0x02
#define CH2_1_F 0x04
#define CH2_2_F 0x08
#define SECOND_F 0x10 // New second flag

#define CH2_OFFSET (32768 - 32748)


/* UART Stuff, macro taken from code by: */
/** Copyright 2002, R O SoftWare
 * No guarantees, warrantees, or promises, implied or otherwise.
 * May be used for hobby or commercial purposes provided copyright
 * notice remains intact. */

/* uart0 1048581Hz 9602bps */
/*
#define UBR00_INIT 0x6D
#define UBR10_INIT 0x00
#define UMCTL0_INIT 0x44
*/

#define USART0_BRCLK      SMCLK

// System Data Rates

///////////////////////////////////////////////////////////////////////////////
// use the following macros to determine the 'baudDiv' parameter values
// for usartInit0() and usartInit1()
// CAUTION - 'baud' SHOULD ALWAYS BE A CONSTANT or
// a lot of code will be generated.
#define USART0_BAUD_DIV(baud) (uint16_t)(USART0_BRCLK / (baud))


///////////////////////////////////////////////////////////////////////////////
// the following are used to calculate the UMOD values at compile time
#define CMOD_0(baud)    ((USART0_BRCLK / (baud)) - USART0_BAUD_DIV(baud))
#define CMOD_1(baud)    ((USART1_BRCLK / (baud)) - USART1_BAUD_DIV(baud))
#define M0_0(baud)      (CMOD_0(baud) + CMOD_0(baud))
#define M0_1(baud)      (CMOD_1(baud) + CMOD_1(baud))
#define M1_0(baud)      (M0_0(baud) + CMOD_0(baud))
#define M1_1(baud)      (M0_1(baud) + CMOD_1(baud))
#define M2_0(baud)      (M1_0(baud) + CMOD_0(baud))
#define M2_1(baud)      (M1_1(baud) + CMOD_1(baud))
#define M3_0(baud)      (M2_0(baud) + CMOD_0(baud))
#define M3_1(baud)      (M2_1(baud) + CMOD_1(baud))
#define M4_0(baud)      (M3_0(baud) + CMOD_0(baud))
#define M4_1(baud)      (M3_1(baud) + CMOD_1(baud))
#define M5_0(baud)      (M4_0(baud) + CMOD_0(baud))
#define M5_1(baud)      (M4_1(baud) + CMOD_1(baud))
#define M6_0(baud)      (M5_0(baud) + CMOD_0(baud))
#define M6_1(baud)      (M5_1(baud) + CMOD_1(baud))
#define M7_0(baud)      (M6_0(baud) + CMOD_0(baud))
#define M7_1(baud)      (M6_1(baud) + CMOD_1(baud))
#define C0_0(baud)      (uint8_t)((int)M0_0(baud) ? BV(0) : 0)
#define C0_1(baud)      (uint8_t)((int)M0_1(baud) ? BV(0) : 0)
#define C1_0(baud)      (uint8_t)(((int)M1_0(baud) - (int)M0_0(baud)) ? BV(1) : 
0)
#define C1_1(baud)      (uint8_t)(((int)M1_1(baud) - (int)M0_1(baud)) ? BV(1) : 
0)
#define C2_0(baud)      (uint8_t)(((int)M2_0(baud) - (int)M1_0(baud)) ? BV(2) : 
0)
#define C2_1(baud)      (uint8_t)(((int)M2_1(baud) - (int)M1_1(baud)) ? BV(2) : 
0)
#define C3_0(baud)      (uint8_t)(((int)M3_0(baud) - (int)M2_0(baud)) ? BV(3) : 
0)
#define C3_1(baud)      (uint8_t)(((int)M3_1(baud) - (int)M2_1(baud)) ? BV(3) : 
0)
#define C4_0(baud)      (uint8_t)(((int)M4_0(baud) - (int)M3_0(baud)) ? BV(4) : 
0)
#define C4_1(baud)      (uint8_t)(((int)M4_1(baud) - (int)M3_1(baud)) ? BV(4) : 
0)
#define C5_0(baud)      (uint8_t)(((int)M5_0(baud) - (int)M4_0(baud)) ? BV(5) : 
0)
#define C5_1(baud)      (uint8_t)(((int)M5_1(baud) - (int)M4_1(baud)) ? BV(5) : 
0)
#define C6_0(baud)      (uint8_t)(((int)M6_0(baud) - (int)M5_0(baud)) ? BV(6) : 
0)
#define C6_1(baud)      (uint8_t)(((int)M6_1(baud) - (int)M5_1(baud)) ? BV(6) : 
0)
#define C7_0(baud)      (uint8_t)(((int)M7_0(baud) - (int)M6_0(baud)) ? BV(7) : 
0)
#define C7_1(baud)      (uint8_t)(((int)M7_1(baud) - (int)M6_1(baud)) ? BV(7) : 
0)

///////////////////////////////////////////////////////////////////////////////
// use the following macros to determine the 'baudMod' parameter values
// CAUTION - 'baud' SHOULD ALWAYS BE A CONSTANT or
// a lot of code will be generated.
#define USART0_BAUD_MOD(baud) (uint8_t)(C7_0(baud) + C6_0(baud) + C5_0(baud) + \
                                        C4_0(baud) + C3_0(baud) + C2_0(baud) + \
                                        C1_0(baud) + C0_0(baud))
 
/* uart0 Init parameters */
#define UBR00_INIT (uint8_t)((uint16_t)(USART0_BRCLK / (HOST_BAUD)) >> 0)
#define UBR10_INIT (uint8_t)((uint16_t)(USART0_BRCLK / (HOST_BAUD)) >> 8)
#define UMCTL0_INIT USART0_BAUD_MOD(HOST_BAUD)
#endif //HARDWARE_H
/*******************************************************************************
* Name:        main.c                                                          *
* Author:      Tennessee Carmel-Veilleux                                       *
* Created:     05/07/2005                                                      *
* Module:      USBVoltAmp mainline code                                        *
* Version:     1.1                                                             *
* Copyright:   (C)2005 Tennessee Carmel-Veilleux                               *
* Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut     *
* utiliser ce code ainsi que tous les fichiers et composants dérivés pour      *
* n'importe quel usage qui lui soit utile.                                     *
*                                                                              *
* Version history:                                                             *
* - 1.0 (05/07/2005): Initial release                                          *
* - 1.1 (06/04/2005): All basic functions implemented                          *
*******************************************************************************/

#include "main.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>

// Buffered UART buffers
volatile unsigned char RxQueue[RX_QUEUE_SIZE];
volatile unsigned char TxQueue[TX_QUEUE_SIZE];
volatile unsigned char RxSize, RxHead, RxTail;
volatile unsigned char TxSize, TxHead, TxTail;

// SD16 buffers and flags
volatile unsigned short SD16Results[4];
volatile unsigned long SD16Timestamps[4];
volatile unsigned char SD16Flags;

// Interval clock counter
volatile uint16 IntervalHi; // Interval clock high part
volatile uint32 IntervalClock; // Interval clock

void InitUART(void);
void Initialization(void);
void delay(unsigned int d);

void InitUART(void) {
    U0CTL  = SWRST; //reset UART

    // Set baud rate
    UBR00 = UBR00_INIT;
    UBR10 = UBR10_INIT;
    UMCTL0 = UMCTL0_INIT; 
    
    U0CTL |= CHAR; // UART ON, 8N1, No loopback
    U0ME |= UTXE0 | URXE0; // Enable USART0 TX and RX (UART mode)
        
    U0TCTL = SSEL_SMCLK | TXEPT;     //use SMCLK
    U0RCTL = 0; // Clear USART0 errors
    
    // Initialize the queue
    TxSize = 0;
    RxSize = 0;
    TxHead = 0;
    RxHead = 0;
    TxTail = 0;
    RxTail = 0;
    
    U0CTL &= ~SWRST; // Unreset UART
    
    IE1 |= UTXIE0 | URXIE0; // Enable USART interrupts
}

void InitSD16(void) {
    // See HARDWARE.H for more info about settings
    SD16CTL = SD16CTL_INIT;
    SD16CCTL0 = SD16CCTL0_INIT;
    SD16CCTL1 = SD16CCTL1_INIT;
    SD16CCTL2 = SD16CCTL2_INIT;
    SD16INCTL0 = SD16INCTL0_INIT; 
    SD16INCTL1 = SD16INCTL1_INIT;
    SD16INCTL2 = SD16INCTL2_INIT;
    
    SD16Flags = 0;
    
    SD16CCTL1 |= SD16SC; // Start conversions on CH0/CH1
    SD16CCTL2 |= SD16SC; // Start conversions on CH2
}

void Initialization(void) {
    FLL_CTL0 = 0x90; // Set XTAL caps to 6pF and DCO_PLUS=1
    
    WDTCTL = WDTCTL_INIT; //Init watchdog timer
    TAR = 0; // Init TimerA counter to 0
    TACTL = TACTL_INIT; // Init TimerA

    P1OUT  = P1OUT_INIT; //Init output data of port1
    P2OUT  = P2OUT_INIT; //Init output data of port2

    P1SEL  = P1SEL_INIT; //Select port or module -function on port1
    P2SEL  = P2SEL_INIT; //Select port or module -function on port2

    P1DIR  = P1DIR_INIT; //Init port direction register of port1
    P2DIR  = P2DIR_INIT; //Init port direction register of port2

    P1IES  = P1IES_INIT; //init port interrupts
    P2IES  = P2IES_INIT;
    P1IE   = P1IE_INIT;
    P2IE   = P2IE_INIT;
    
    IE1 |= WDTIE; // Enable watchdog timer interrupt

    InitUART();
    InitSD16();
}

/**
Delay function.
*/
void delay(unsigned int d) {
   int i;
   for (i = 0; i<d; i++) {
      nop();
      nop();
   }
}

void blink(int n) {
    int i;
    
    for (i = 0; i < n; i++) {
        P2OUT |= LED0;
        delay(0x4000);
        P2OUT &= ~LED0;
        delay(0x4000);
    }
}

/**
Main function with some blinking leds
*/
int main(void) {
    unsigned short i = 0;
    int count[4];
    unsigned int value[4];
    
    Initialization();
    eint();
    delay(0x400);
    
    blink(3);
    
    while (1) {                         //main loop, never ends...
        if (SD16Flags & CH0_F) {
            count[0] ++;
            value[0] = SD16Results[0];
            SD16Flags &= ~CH0_F;    
        }
        
        if (SD16Flags & CH1_F) {
            count[1] ++;
            value[1] = SD16Results[1];
            SD16Flags &= ~CH1_F;    
        }
        
        if (SD16Flags & CH2_1_F) {
            count[2] ++;
            value[2] = SD16Results[2];
            SD16Flags &= ~CH2_1_F;    
        }
        
        if (SD16Flags & CH2_2_F) {
            count[3] ++;
            value[3] = ((SD16Results[3] + (unsigned int)CH2_OFFSET) - 0x7FFF) 
>> 4;
            SD16Flags &= ~CH2_2_F;
            printf("%5u,%5u,%5u,%5u\n\r",value[0],value[1],value[2],value[3]);  
          
            //printf("%5u\n\r",value[3]);            
        }
        
        if (SD16Flags & SECOND_F) {
            printf("%2u,%2u,%2u,%2u\n\r",count[0],count[1],count[2],count[3]);
            count[0] = count[1] = count[2] = count[3] = 0;
            SD16Flags &= ~SECOND_F;
            P2OUT ^= LED0;
        }
    }
}

/*******************************************************************************
* Name:        main.h                                                          *
* Author:      Tennessee Carmel-Veilleux                                       *
* Created:     05/07/2005                                                      *
* Module:      USBVoltAmp mainline code header                                 *
* Version:     1.1                                                             *
* Copyright:   (C)2005 Tennessee Carmel-Veilleux                               *
* Le Laboratoire de Robotique Pédagogique de l'Université de Montréal peut     *
* utiliser ce code ainsi que tous les fichiers et composants dérivés pour      *
* n'importe quel usage qui lui soit utile.                                     *
*                                                                              *
* Version history:                                                             *
* - 1.0 (05/07/2005): Initial release                                          *
* - 1.1 (06/04/2005): All basic functions implemented                          *
*******************************************************************************/
#include <sys/inttypes.h>
#include "hardware.h"
#include "asmlib.h"

// Nombre de commandes
#define MAX_COMMANDES 16
// Longueur max de commande
#define LG_SYMB 6
// Longueur max de ligne de commande
#define LG_STRING 32
// Nombre de paramètres MAX
#define N_PARAM 6

#define putc(c) putchar(c)
#define kbhit() (RxSize != 0)

typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;

extern int parametre[N_PARAM];  // paramètres de la ligne de commande
extern int code; // Code de commande
extern int debug; // Flag de débug
extern uint8 EEbuf[128]; // Buffer d'EEPROM (info flash)
extern volatile uint16 IntervalHi; // Interval timer high part
extern volatile uint32 IntervalClock; // Interval Timer

// Fonctions et commandes de l'interpréteur

void ResetInterval(void);

void PORT(void);
void ECHO(void);
void WMEM(void);
void RMEM(void);
void MES(void);
void EA(void);
void RECO(void);
void CHAN(void);
void FILT(void);
void GAIN(void);
void ACQ(void);
void APPLY(void);
void DUMP(void);
void RAW(void);
void CLR(void);
void CLK(void);

Reply via email to