After numerous unsuccessful attempts at modifying the boot_serial project and using the assembly start up code provide; while seeing many strange behaviors, such as changing behaviors with levels of compiler optimization, strange sp and lr addresses, change the GPIO Forced Update assignment breaking the program at a different later point, and sometimes variables/pointers simply just not setting after stepping through the statement --
This is my latest attempt at creating a SD Card bootloader that is as simple as possible and easy to understand as possible.
This seems correct in theory and should be useful to someone else as well...
The start up script is nothing special, just the one provided through Keil. fatfs files are the ones included with TivaWare.
With this build:
I am seeing the SP changed to 0x1fffff60 right as I step to f_mount(0, &fatFs);
so then I moved the following to a global area:
FATFS fatFs; FIL fileObject; FRESULT fResult;
This way they would not be allocated using the stack, just to see what happens, since this data shouldnt't be causing a stack overflow or any issues in the first place. I don't see the erratic stack pointer. But at some arbitrary point later LR is set to 0xfffffff9 and the program goes into HardFault_Handler.
I really cannot explain this behavior any way.
The APP_START_ADDRESS 0x2800 was actually flashed with boot_demo2 using another program. I am able to jump from boot_demo2 back to the Bootloader program... but for some reason going into the fatfs functions, strange things occur. I know the problem is not with the fatfs code, it has work with other projects.
//*****************************************************************************
//
// bl_main.c - The file holds the main control loop of the boot loader.
//
// Copyright (c) 2006-2016 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 2.1.3.156 of the Tiva Firmware Development Package.
//
//*****************************************************************************
//*****************************************************************************
//
// Convert to SD boot loader and test with boot demo 1 and 2
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_gpio.h"
#include "inc/hw_nvic.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "fatfs/src/ff.h"
#include "fatfs/src/diskio.h"
//#include "pff3/src/pff.h" /* Petit FatFs configurations and declarations */
//#include "pff3/src/diskio.h" /* Declarations of low level disk I/O functions */
//#include "pff3/src/pffconf.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
//*****************************************************************************
//
// Make sure that the application start address falls on a flash page boundary
//
//*****************************************************************************
#if (APP_START_ADDRESS & (FLASH_PAGE_SIZE - 1))
#error ERROR: APP_START_ADDRESS must be a multiple of FLASH_PAGE_SIZE bytes!
#endif
//*****************************************************************************
//
// Make sure that the flash reserved space is a multiple of flash pages.
//
//*****************************************************************************
#if (FLASH_RSVD_SPACE & (FLASH_PAGE_SIZE - 1))
#error ERROR: FLASH_RSVD_SPACE must be a multiple of FLASH_PAGE_SIZE bytes!
#endif
//*****************************************************************************
//
// The starting address of the application. This must be a multiple of 1024
// bytes (making it aligned to a page boundary). A vector table is expected at
// this location, and the perceived validity of the vector table (stack located
// in SRAM, reset vector located in flash) is used as an indication of the
// validity of the application image.
//
// The flash image of the boot loader must not be larger than this value.
//
// Depends on: None
// Exclusive of: None
// Requires: None
//
//*****************************************************************************
#define APP_START_ADDRESS 0x2800
//*****************************************************************************
//
// The address at which the application locates its exception vector table.
// This must be a multiple of 1024 bytes (making it aligned to a page
// boundary). Typically, an application will start with its vector table and
// this value should be set to APP_START_ADDRESS. This option is provided to
// cater for applications which run from external memory which may not be
// accessible by the NVIC (the vector table offset register is only 30 bits
// long).
//
// Depends on: None
// Exclusive of: None
// Requires: None
//
//*****************************************************************************
#define VTABLE_START_ADDRESS 0x2800
//*****************************************************************************
//
// The size of a single, erasable page in the flash. This must be a power
// of 2.
//
// Depends on: None
// Exclusive of: None
// Requires: None
//
//*****************************************************************************
#define FLASH_PAGE_SIZE 0x00000400
//*****************************************************************************
//
// The GPIO module to enable in order to check for a forced update. This will
// be one of the SYSCTL_RCGC2_GPIOx values, where "x" is replaced with the port
// name (such as B). The value of "x" should match the value of "x" for
// FORCED_UPDATE_PORT.
//
// Depends on: ENABLE_UPDATE_CHECK
// Exclusive of: None
// Requries: None
//
//*****************************************************************************
//#define FORCED_UPDATE_PERIPH SYSCTL_RCGC2_GPIOB
#define FORCED_UPDATE_PERIPH 0x00000800 // for GPIOM
//*****************************************************************************
//
// The GPIO port to check for a forced update. This will be one of the
// GPIO_PORTx_BASE values, where "x" is replaced with the port name (such as
// B). The value of "x" should match the value of "x" for
// FORCED_UPDATE_PERIPH.
//
// Depends on: ENABLE_UPDATE_CHECK
// Exclusive of: None
// Requries: None
//
//*****************************************************************************
#define FORCED_UPDATE_PORT GPIO_PORTM_BASE
//*****************************************************************************
//
// The pin to check for a forced update. This is a value between 0 and 7.
//
// Depends on: ENABLE_UPDATE_CHECK
// Exclusive of: None
// Requries: None
//
//*****************************************************************************
#define FORCED_UPDATE_PIN 0
//*****************************************************************************
//
// The polarity of the GPIO pin that results in a forced update. This value
// should be 0 if the pin should be low and 1 if the pin should be high.
//
// Depends on: ENABLE_UPDATE_CHECK
// Exclusive of: None
// Requries: None
//
//*****************************************************************************
#define FORCED_UPDATE_POLARITY 0
//*****************************************************************************
//
// This enables a weak pull-up or pull-down for the GPIO pin used in a forced
// update. Only one of FORCED_UPDATE_WPU or FORCED_UPDATE_WPD should be
// defined, or neither if a weak pull-up or pull-down is not required.
//
// Depends on: ENABLE_UPDATE_CHECK
// Exclusive of: None
// Requries: None
//
//*****************************************************************************
#define FORCED_UPDATE_WPU
//#define FORCED_UPDATE_WPD
//*****************************************************************************
//
// This enables the use of the GPIO_LOCK mechanism for configuration of
// protected GPIO pins (for example JTAG pins). If this value is not defined,
// the locking mechanism will not be used. The only legal values for this
// feature are GPIO_LOCK_KEY for Fury devices and GPIO_LOCK_KEY_DD for all
// other devices except Sandstorm devices, which do not support this feature.
//
// Depends on: ENABLE_UPDATE_CHECK
// Exclusive of: None
// Requries: None
//
//*****************************************************************************
//#define FORCED_UPDATE_KEY GPIO_LOCK_KEY
//#define FORCED_UPDATE_KEY GPIO_LOCK_KEY_DD
#define Delay(n) ROM_SysCtlDelay((ROM_SysCtlClockGet()/3000000)*n)
//extern void CallApplication();
uint32_t g_ui32Forced = 0;
//*****************************************************************************
//
//! Checks a GPIO for a forced update.
//!
//! This function checks the state of a GPIO to determine if a update is being
//! requested.
//!
//! \return Returns a non-zero value if an update is being requested and zero
//! otherwise.
//
//*****************************************************************************
uint32_t
CheckGPIOForceUpdate(void)
{
//
// Enable the required GPIO module.
//
HWREG(SYSCTL_RCGCGPIO) |= FORCED_UPDATE_PERIPH;
//
// Wait a while before accessing the peripheral.
//
Delay(3);
#ifdef FORCED_UPDATE_KEY
//
// Unlock the GPIO Access.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_LOCK) = FORCED_UPDATE_KEY;
HWREG(FORCED_UPDATE_PORT + GPIO_O_CR) = 1 << FORCED_UPDATE_PIN;
#endif
//
// Enable the pin used to see if an update is being requested.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_DEN) |= 1 << FORCED_UPDATE_PIN;
#ifdef FORCED_UPDATE_WPU
//
// Set the output drive strength.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_DR2R) |= 1 << FORCED_UPDATE_PIN;
//
// Enable the weak pull up.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_PUR) |= 1 << FORCED_UPDATE_PIN;
//
// Make sure that the analog mode select register is clear for this pin.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_AMSEL) &= ~(1 << FORCED_UPDATE_PIN);
#endif
#ifdef FORCED_UPDATE_WPD
//
// Set the output drive strength.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_DR2R) |= 1 << FORCED_UPDATE_PIN;
//
// Enable the weak pull down.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_PDR) |= 1 << FORCED_UPDATE_PIN;
//
// Make sure that the analog mode select register is clear for this pin.
// This register only appears in DustDevil-class (and later) devices, but
// is a harmless write on Sandstorm- and Fury-class devices.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_AMSEL) &= ~(1 << FORCED_UPDATE_PIN);
#endif
#ifdef FORCED_UPDATE_KEY
//
// Unlock the GPIO Access.
//
HWREG(FORCED_UPDATE_PORT + GPIO_O_LOCK) = FORCED_UPDATE_KEY;
HWREG(FORCED_UPDATE_PORT + GPIO_O_CR) = 0;
#endif
//
// Wait a while before reading the pin.
//
Delay(1000);
//
// Check the pin to see if an update is being requested.
//
if(HWREG(FORCED_UPDATE_PORT + (1 << (FORCED_UPDATE_PIN + 2))) ==
(FORCED_UPDATE_POLARITY << FORCED_UPDATE_PIN))
{
//
// Remember that this was a forced update.
//
g_ui32Forced = 1;
return(1);
}
//
// No update is being requested so return 0.
//
return(0);
}
//*****************************************************************************
//
//! Checks if an update is needed or is being requested.
//!
//! This function detects if an update is being requested or if there is no
//! valid code presently located on the microcontroller. This is used to tell
//! whether or not to enter update mode.
//!
//! \return Returns a non-zero value if an update is needed or is being
//! requested and zero otherwise.
//
//*****************************************************************************
uint32_t
CheckForceUpdate(void)
{
uint32_t *pui32App;
//
// See if the first location is 0xfffffffff or something that does not
// look like a stack pointer, or if the second location is 0xffffffff or
// something that does not look like a reset vector.
//
pui32App = (uint32_t *)APP_START_ADDRESS;
if((pui32App[0] == 0xffffffff) ||
((pui32App[0] & 0xfff00000) != 0x20000000) ||
(pui32App[1] == 0xffffffff) ||
((pui32App[1] & 0xfff00001) != 0x00000001))
{
return(1);
}
//
// If simple GPIO checking is configured, determine whether or not to force
// an update.
//
return(CheckGPIOForceUpdate());
}
//*****************************************************************************
//
//! Configures the microcontroller.
//!
//! This function configures the peripherals and GPIOs of the microcontroller,
//! preparing it for use by the boot loader. The interface that has been
//! selected as the update port will be configured, and auto-baud will be
//! performed if required.
//!
//! \return None.
//
//*****************************************************************************
void
ConfigureDevice(void)
{
//
// Since the crystal frequency was specified, enable the main oscillator
// and clock the processor from it.
//
// HWREG(SYSCTL_RCC) &= ~(SYSCTL_RCC_MOSCDIS);
// Delay(524288);
// HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_OSCSRC_M)) |
// SYSCTL_RCC_OSCSRC_MAIN);
// ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_INT | SYSCTL_MAIN_OSC_DIS); //Enable for ROM_SysCtlDelay
int nStatus;
HWREG(SYSCTL_RCGCGPIO) &= ~FORCED_UPDATE_PERIPH;
ROM_SysCtlClockSet(SYSCTL_USE_OSC | SYSCTL_OSC_INT);
nStatus = ROM_SysCtlClockGet();
//
// Configure SysTick for a 100Hz interrupt. The FatFs driver wants a 10 ms
// tick.
//
ROM_SysTickPeriodSet(ROM_SysCtlClockGet() / 100);
ROM_SysTickEnable();
ROM_SysTickIntEnable();
ROM_IntMasterEnable();
}
//*****************************************************************************
//
//! This function performs the update on the selected port.
//!
//! This function is called directly by the boot loader or it is called as a
//! result of an update request from the application.
//!
//! \return Never returns.
//
//*****************************************************************************
void
Updater(void)
{
FATFS fatFs;
FIL fileObject;
FRESULT fResult;
uint32_t addr, count, data, temp;
fResult = f_mount(0, &fatFs);
//fResult = pf_mount(&fatFs);
if(fResult == FR_OK)
{
fResult = f_open(&fileObject, "boot2.bin", FA_READ);
//fResult = pf_open("boot2.bin");
// temp = 0;
// do
// {
// fResult = pf_open("boot2.bin");
// temp++;
// } while (temp < 10 && (fResult != FR_OK) );
if(fResult == FR_OK)
{
for(addr = APP_START_ADDRESS; addr < APP_START_ADDRESS + fileObject.fsize; addr += FLASH_PAGE_SIZE)
//for(addr = APP_START_ADDRESS; addr < APP_START_ADDRESS + fatFs.fsize; addr += FLASH_PAGE_SIZE)
{
//
// Erase this block.
//
ROM_FlashErase(addr);
}
for(addr = APP_START_ADDRESS; addr < APP_START_ADDRESS + fileObject.fsize; addr += 4)
//for(addr = APP_START_ADDRESS; addr < APP_START_ADDRESS + fatFs.fsize; addr += 4)
{
//
// Write data to the flash 4 bytes at a time
//
f_read(&fileObject, &data, 4, &count);
//pf_read(&data, 4, &count);
ROM_FlashProgram(&data, addr, 4);
}
}
}
// HWREG(NVIC_APINT) = (NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ);
while(1);
}
//*****************************************************************************
//
// This is the handler for this SysTick interrupt. FatFs requires a timer tick
// every 10 ms for internal timing purposes.
//
//*****************************************************************************
void
SysTickHandler(void)
{
//
// Call the FatFs tick timer.
//
disk_timerproc();
}
void SVC_Handler (void)
{
ConfigureDevice();
Updater();
while(1);
}
int
main(void)
{
uint32_t t = 213 ;
t = ROM_SysCtlClockGet();
if (CheckForceUpdate())
{
ConfigureDevice();
Updater();
}
else
{
ROM_SysTickIntDisable();
ROM_SysTickDisable();
HWREG(NVIC_DIS0) = 0xffffffff;
HWREG(NVIC_DIS1) = 0xffffffff;
(*((void (*)(void))(*(uint32_t *)(APP_START_ADDRESS+4))))();
}
while(1);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************