summaryrefslogtreecommitdiff
path: root/boot_loader/bl_autobaud.c
diff options
context:
space:
mode:
Diffstat (limited to 'boot_loader/bl_autobaud.c')
-rw-r--r--boot_loader/bl_autobaud.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/boot_loader/bl_autobaud.c b/boot_loader/bl_autobaud.c
new file mode 100644
index 0000000..1600c71
--- /dev/null
+++ b/boot_loader/bl_autobaud.c
@@ -0,0 +1,279 @@
+//*****************************************************************************
+//
+// bl_autobaud.c - Automatic baud rate detection code.
+//
+// Copyright (c) 2006-2014 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.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_types.h"
+#include "bl_config.h"
+#include "boot_loader/bl_uart.h"
+
+//*****************************************************************************
+//
+// If using auto-baud, make sure that the data buffer is large enough.
+//
+//*****************************************************************************
+#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) && (BUFFER_SIZE < 20)
+#error ERROR: BUFFER_SIZE must be >= 20!
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup bl_autobaud_api
+//! @{
+//
+//*****************************************************************************
+#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+// This define holds the multiplier for the pulse detection algorithm. The
+// value is used to generate a fractional difference detection of
+// 1 / PULSE_DETECTION_MULT.
+//
+//*****************************************************************************
+#define PULSE_DETECTION_MULT 3
+
+//*****************************************************************************
+//
+// This define holds the minimum number of edges to successfully sync to a
+// pattern of 2 bytes.
+//
+//*****************************************************************************
+#define MIN_EDGE_COUNT 18
+
+//*****************************************************************************
+//
+// This global holds the number of edges that have been stored in the global
+// buffer g_pui32DataBuffer.
+//
+//*****************************************************************************
+static volatile uint32_t g_ui32TickIndex;
+
+//*****************************************************************************
+//
+// The data buffer that is used for receiving packets is used to hold the edge
+// times during auto-baud. The buffer is not used for receiving packets while
+// auto-baud is in progress, so this does not present problems.
+//
+//*****************************************************************************
+extern uint32_t g_pui32DataBuffer[];
+
+//*****************************************************************************
+//
+//! Handles the UART Rx GPIO interrupt.
+//!
+//! When an edge is detected on the UART Rx pin, this function is called to
+//! save the time of the edge. These times are later used to determine the
+//! ratio of the UART baud rate to the processor clock rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+GPIOIntHandler(void)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Clear the GPIO interrupt source.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_ICR) = UART_RX;
+
+ //
+ // While we still have space in our buffer, store the current system tick
+ // count and return from interrupt.
+ //
+ if(g_ui32TickIndex < 20)
+ {
+ ui32Temp = HWREG(NVIC_ST_CURRENT);
+ g_pui32DataBuffer[g_ui32TickIndex++] = ui32Temp;
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs auto-baud on the UART port.
+//!
+//! \param pui32Ratio is the ratio of the processor's crystal frequency to the
+//! baud rate being used by the UART port for communications.
+//!
+//! This function attempts to synchronize to the updater program that is trying
+//! to communicate with the boot loader. The UART port is monitored for edges
+//! using interrupts. Once enough edges are detected, the boot loader
+//! determines the ratio of baud rate and crystal frequency needed to program
+//! the UART.
+//!
+//! \return Returns a value of 0 to indicate that this call successfully
+//! synchronized with the other device communicating over the UART, and a
+//! negative value to indicate that this function did not successfully
+//! synchronize with the other UART device.
+//
+//*****************************************************************************
+int
+UARTAutoBaud(uint32_t *pui32Ratio)
+{
+ int32_t i32Pulse, i32ValidPulses, i32Temp, i32Total;
+ volatile int32_t i32Delay;
+
+ //
+ // Configure and enable SysTick. Set the reload value to the maximum;
+ // there are only 24 bits in the register but loading 32 bits of ones is
+ // more efficient.
+ //
+ HWREG(NVIC_ST_RELOAD) = 0xffffffff;
+ HWREG(NVIC_ST_CTRL) = NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_ENABLE;
+
+ //
+ // Reset the counters that control the pulse detection.
+ //
+ i32ValidPulses = 0;
+ i32Total = 0;
+ g_ui32TickIndex = 0;
+
+ //
+ // Set the pad(s) for standard push-pull operation.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_PUR) |= UART_RX;
+ HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= UART_RX;
+
+ //
+ // Interrupt on both edges.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_IBE) = UART_RX;
+
+ //
+ // Clear out all of the gpio interrupts in this register.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_ICR) = UART_RX;
+
+ //
+ // Enable the GPIO pin corresponding to the UART RX pin.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_IM) = UART_RX;
+
+ //
+ // Enable GPIOA Interrupt.
+ //
+ HWREG(NVIC_EN0) = 1;
+
+ //
+ // Wait for MIN_EDGE_COUNT to pass to collect enough edges.
+ //
+ while(g_ui32TickIndex < MIN_EDGE_COUNT)
+ {
+ }
+
+ //
+ // Disable GPIOA Interrupt.
+ //
+ HWREG(NVIC_DIS0) = 1;
+
+ //
+ // Calculate the pulse widths from the array of tick times.
+ //
+ for(i32Pulse = 0; i32Pulse < (MIN_EDGE_COUNT - 1); i32Pulse++)
+ {
+ i32Temp = (((int32_t)g_pui32DataBuffer[i32Pulse] -
+ (int32_t)g_pui32DataBuffer[i32Pulse + 1]) & 0x00ffffff);
+ g_pui32DataBuffer[i32Pulse] = i32Temp;
+ }
+
+ //
+ // This loops handles checking for consecutive pulses that have pulse
+ // widths that are within an acceptable margin.
+ //
+ for(i32Pulse = 0; i32Pulse < (MIN_EDGE_COUNT - 1); i32Pulse++)
+ {
+ //
+ // Calculate the absolute difference between two consecutive pulses.
+ //
+ i32Temp = (int32_t)g_pui32DataBuffer[i32Pulse];
+ i32Temp -= (int32_t)g_pui32DataBuffer[i32Pulse + 1];
+ if(i32Temp < 0)
+ {
+ i32Temp *= -1;
+ }
+
+ //
+ // This pulse detection code uses the following algorithm:
+ // If the following is true then we have consecutive acceptable pulses
+ // abs(Pulse[n] - Pulse[n + 1]) < Pulse[n + 1] / PULSE_DETECTION_MULT
+ // or
+ // PULSE_DETECTION_MULT * abs(Pulse[n] - Pulse[n + 1]) < Pulse[n + 1]
+ //
+ if((i32Temp * PULSE_DETECTION_MULT) <
+ (int32_t)g_pui32DataBuffer[i32Pulse + 1])
+ {
+ i32Total += (int32_t)g_pui32DataBuffer[i32Pulse];
+ i32ValidPulses++;
+ }
+ else
+ {
+ i32ValidPulses = 0;
+ i32Total = 0;
+ }
+
+ //
+ // Once we have 7 pulses calculate the ratio needed to program the
+ // UART.
+ //
+ if(i32ValidPulses == 7)
+ {
+ //
+ // Add in the last pulse and calculate the ratio.
+ //
+ i32Total += (int32_t)g_pui32DataBuffer[i32Pulse];
+ *pui32Ratio = i32Total >> 1;
+
+ //
+ // Wait for at least 2 UART clocks since we only wait for 18 of 20
+ // that are coming from the host. If we don't wait, we can turn
+ // on the UART while the last two pulses come down.
+ //
+ for(i32Delay = i32Total; i32Delay; i32Delay--)
+ {
+ }
+
+ //
+ // Indicate a successful auto baud operation.
+ //
+ return(0);
+ }
+ }
+
+ //
+ // Automatic baud rate detection failed.
+ //
+ return(-1);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif