📄 bl_main.c
字号:
//*****************************************************************************
//
// bl_main.c - The file holds the main control loop of the boot loader.
//
// Copyright (c) 2006-2007 Luminary Micro, Inc. All rights reserved.
//
// Software License Agreement
//
// Luminary Micro, Inc. (LMI) is supplying this software for use solely and
// exclusively on LMI's microcontroller products.
//
// The software is owned by LMI and/or its suppliers, and is protected under
// applicable copyright laws. All rights are reserved. You may not combine
// this software with "viral" open-source software in order to form a larger
// program. Any use in violation of the foregoing restrictions may subject
// the user to criminal sanctions under applicable laws, as well as to civil
// liability for the breach of the terms and conditions of this license.
//
// THIS SOFTWARE IS PROVIDED "AS IS". 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.
// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 1928 of the Stellaris Peripheral Driver Library.
//
//*****************************************************************************
#include "../hw_gpio.h"
#include "../hw_flash.h"
#include "../hw_i2c.h"
#include "../hw_memmap.h"
#include "../hw_nvic.h"
#include "../hw_ssi.h"
#include "../hw_sysctl.h"
#include "../hw_types.h"
#include "../hw_uart.h"
#include "bl_commands.h"
#include "bl_config.h"
#include "bl_decrypt.h"
#include "bl_i2c.h"
#include "bl_packet.h"
#include "bl_ssi.h"
#include "bl_uart.h"
//*****************************************************************************
//
// Make sure that the application start address is a multiple of 1024 bytes.
//
//*****************************************************************************
#if (APP_START_ADDRESS & 0x3ff)
#error ERROR: APP_START_ADDRESS must be a multiple of 1024 bytes!
#endif
//*****************************************************************************
//
// Make sure that the flash reserved space is a multiple of 1024 bytes.
//
//*****************************************************************************
#if (FLASH_RSVD_SPACE & 0x3ff)
#error ERROR: FLASH_RSVD_SPACE must be a multiple of 1024 bytes!
#endif
//*****************************************************************************
//
//! \addtogroup boot_loader_api
//! @{
//
//*****************************************************************************
#if defined(I2C_ENABLE_UPDATE) || defined(SSI_ENABLE_UPDATE) || \
defined(UART_ENABLE_UPDATE) || defined(DOXYGEN)
//*****************************************************************************
//
// A prototype for the function (in the startup code) for calling the
// application.
//
//*****************************************************************************
extern void CallApplication(unsigned long ulBase);
//*****************************************************************************
//
// A prototype for the function (in the startup code) for a predictable length
// delay.
//
//*****************************************************************************
extern void Delay(unsigned long ulCount);
//*****************************************************************************
//
// Holds the current status of the last command that was issued to the boot
// loader.
//
//*****************************************************************************
unsigned char g_ucStatus;
//*****************************************************************************
//
// This holds the current remaining size in bytes to be downloaded.
//
//*****************************************************************************
unsigned long g_ulTransferSize;
//*****************************************************************************
//
// This holds the current address that is being written to during a download
// command.
//
//*****************************************************************************
unsigned long g_ulTransferAddress;
//*****************************************************************************
//
// This is the data buffer used during transfers to the boot loader.
//
//*****************************************************************************
unsigned long g_pulDataBuffer[BUFFER_SIZE];
//*****************************************************************************
//
// This is an specially aligned buffer pointer to g_pulDataBuffer to make
// copying to the buffer simpler. It must be offset to end on an address that
// ends with 3.
//
//*****************************************************************************
unsigned char *g_pucDataBuffer;
//*****************************************************************************
//
// Converts a word from big endian to little endian. This macro uses compiler-
// specific constructs to perform an inline insertion of the "rev" instruction,
// which performs the byte swap directly.
//
//*****************************************************************************
#define ewarm
#if defined(ewarm)
#include <intrinsics.h>
#define SwapWord(x) __REV(x)
#endif
#if defined(gcc) || defined(sourcerygxx)
#define SwapWord(x) __extension__ \
({ \
register unsigned long __ret, __inp = x; \
__asm__("rev %0, %1" : "=r" (__ret) : "r" (__inp)); \
__ret; \
})
#endif
#if defined(rvmdk) || defined(__ARMCC_VERSION)
#define SwapWord(x) __rev(x)
#endif
//*****************************************************************************
//
//! 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.
//!
//! This function is contained in <tt>bl_main.c</tt>.
//!
//! \return None.
//
//*****************************************************************************
void
ConfigureDevice(void)
{
#ifdef UART_ENABLE_UPDATE
unsigned long ulProcRatio;
#endif
#ifdef CRYSTAL_FREQ
//
// 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);
//
// Set the flash programming time based on the specified crystal frequency.
//
HWREG(FLASH_USECRL) = ((CRYSTAL_FREQ + 999999) / 1000000) - 1;
#else
//
// Set the flash to program at 16 MHz since that is just beyond the fastest
// that we could run.
//
HWREG(FLASH_USECRL) = 15;
#endif
#ifdef I2C_ENABLE_UPDATE
//
// Enable the clocks to the I2C and GPIO modules.
//
HWREG(SYSCTL_RCGC2) = SYSCTL_RCGC2_GPIOB;
HWREG(SYSCTL_RCGC1) = SYSCTL_RCGC1_I2C0;
//
// Configure the GPIO pins for hardware control, open drain with pull-up,
// and enable them.
//
HWREG(GPIO_PORTB_BASE + GPIO_O_AFSEL) = (1 << 7) | I2C_PINS;
HWREG(GPIO_PORTB_BASE + GPIO_O_DEN) = (1 << 7) | I2C_PINS;
HWREG(GPIO_PORTB_BASE + GPIO_O_ODR) = I2C_PINS;
//
// Enable the I2C Slave Mode.
//
HWREG(I2C0_MASTER_BASE + I2C_O_MCR) = I2C_MCR_MFE | I2C_MCR_SFE;
//
// Setup the I2C Slave Address.
//
HWREG(I2C0_SLAVE_BASE + I2C_O_SOAR) = I2C_SLAVE_ADDR;
//
// Enable the I2C Slave Device on the I2C bus.
//
HWREG(I2C0_SLAVE_BASE + I2C_O_SCSR) = I2C_SCSR_DA;
#endif
#ifdef SSI_ENABLE_UPDATE
//
// Enable the clocks to the SSI and GPIO modules.
//
HWREG(SYSCTL_RCGC2) = SYSCTL_RCGC2_GPIOA;
HWREG(SYSCTL_RCGC1) = SYSCTL_RCGC1_SSI0;
//
// Make the pin be peripheral controlled.
//
HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) = SSI_PINS;
HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) = SSI_PINS;
//
// Set the SSI protocol to Motorola with default clock high and data
// valid on the rising edge.
//
HWREG(SSI0_BASE + SSI_O_CR0) = (SSI_CR0_SPH | SSI_CR0_SPO |
(DATA_BITS_SSI - 1));
//
// Enable the SSI interface in slave mode.
//
HWREG(SSI0_BASE + SSI_O_CR1) = SSI_CR1_MS | SSI_CR1_SSE;
#endif
#ifdef UART_ENABLE_UPDATE
//
// Enable the the clocks to the UART and GPIO modules.
//
HWREG(SYSCTL_RCGC2) = SYSCTL_RCGC2_GPIOA;
HWREG(SYSCTL_RCGC1) = SYSCTL_RCGC1_UART0;
//
// Keep attempting to sync until we are successful.
//
#ifdef UART_AUTOBAUD
while(UARTAutoBaud(&ulProcRatio) < 0)
{
}
#else
ulProcRatio = UART_BAUD_RATIO(UART_FIXED_BAUDRATE);
#endif
//
// Set GPIO A0 and A1 as UART pins.
//
HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) = UART_PINS;
//
// Set the pin type.
//
HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) = UART_PINS;
//
// Set the baud rate.
//
HWREG(UART0_BASE + UART_O_IBRD) = ulProcRatio >> 6;
HWREG(UART0_BASE + UART_O_FBRD) = ulProcRatio & UART_FBRD_DIVFRAC_M;
//
// Set data length, parity, and number of stop bits to 8-N-1.
//
HWREG(UART0_BASE + UART_O_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;
//
// Enable RX, TX, and the UART.
//
HWREG(UART0_BASE + UART_O_CTL) = (UART_CTL_UARTEN | UART_CTL_TXE |
UART_CTL_RXE);
#ifdef UART_AUTOBAUD
//
// Need to ack in the UART case to hold it up while we get things set up.
//
AckPacket();
#endif
#endif
}
//*****************************************************************************
//
//! 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.
//!
//! This function is contained in <tt>bl_main.c</tt>.
//!
//! \return Never returns.
//
//*****************************************************************************
void
Updater(void)
{
unsigned long ulSize, ulTemp, ulFlashSize;
//
// This ensures proper alignment of the global buffer so that the one byte
// size parameter used by the packetized format is easily skipped for data
// transfers.
//
g_pucDataBuffer = ((unsigned char *)g_pulDataBuffer) + 3;
//
// Insure that the COMMAND_SEND_DATA cannot be sent to erase the boot
// loader before the application is erased.
//
g_ulTransferAddress = 0xffffffff;
//
// Read any data from the serial port in use.
//
while(1)
{
//
// Receive a packet from the port in use.
//
ulSize = sizeof(g_pulDataBuffer) - 3;
if(ReceivePacket(g_pucDataBuffer, &ulSize) != 0)
{
continue;
}
//
// The first byte of the data buffer has the command and determines
// the format of the rest of the bytes.
//
switch(g_pucDataBuffer[0])
{
//
// This was a simple ping command.
//
case COMMAND_PING:
{
//
// This command always sets the status to COMMAND_RET_SUCCESS.
//
g_ucStatus = COMMAND_RET_SUCCESS;
//
// Just acknowledge that the command was received.
//
AckPacket();
//
// Go back and wait for a new command.
//
break;
}
//
// This command indicates the start of a download sequence.
//
case COMMAND_DOWNLOAD:
{
//
// Until determined otherwise, the command status is success.
//
g_ucStatus = COMMAND_RET_SUCCESS;
//
// A simple do/while(0) control loop to make error exits
// easier.
//
do
{
//
// See if a full packet was received.
//
if(ulSize != 9)
{
//
// Indicate that an invalid command was received.
//
g_ucStatus = COMMAND_RET_INVALID_CMD;
//
// This packet has been handled.
//
break;
}
//
// Get the address and size from the command.
//
g_ulTransferAddress = SwapWord(g_pulDataBuffer[1]);
g_ulTransferSize = SwapWord(g_pulDataBuffer[2]);
//
// This determines the size of the flash available on the
// part in use.
//
ulFlashSize = (((HWREG(SYSCTL_DC0) &
SYSCTL_DC0_FLASHSZ_M) + 1) << 11);
//
// If we are reserving space at the top of flash then this
// space is not available for application download but it
// is availble to be updated directly.
//
#ifdef FLASH_RSVD_SPACE
if((ulFlashSize - FLASH_RSVD_SPACE) != g_ulTransferAddress)
{
ulFlashSize -= FLASH_RSVD_SPACE;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -