libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers board.cpp Source File

board.cpp

00001 /*
00002  * Pavel Kirienko, 2014 <pavel.kirienko@gmail.com>
00003  * Board initialization for Olimex LPC11C24
00004  */
00005 
00006 #include "board.hpp"
00007 #include <chip.h>
00008 #include <cstdlib>
00009 #include <cstring>
00010 #include <numeric>
00011 
00012 static constexpr unsigned long PDRUNCFGUSEMASK = 0x0000ED00U;
00013 static constexpr unsigned long PDRUNCFGMASKTMP = 0x000000FFU;
00014 
00015 const std::uint32_t OscRateIn = 12000000; ///< External crystal
00016 const std::uint32_t ExtRateIn = 0;
00017 
00018 std::uint32_t SystemCoreClock = 12000000; ///< Initialized to default clock value, will be changed on init
00019 
00020 namespace board
00021 {
00022 namespace
00023 {
00024 
00025 constexpr unsigned TargetSystemCoreClock = 48000000;
00026 
00027 constexpr unsigned ErrorLedPort = 1;
00028 constexpr unsigned ErrorLedPin  = 10;
00029 
00030 constexpr unsigned StatusLedPort = 1;
00031 constexpr unsigned StatusLedPin  = 11;
00032 
00033 struct PinMuxGroup
00034 {
00035     unsigned pin      : 8;
00036     unsigned modefunc : 24;
00037 };
00038 
00039 constexpr PinMuxGroup pinmux[] =
00040 {
00041     { IOCON_PIO1_10, IOCON_FUNC0 | IOCON_MODE_INACT },                                          // Error LED
00042     { IOCON_PIO1_11, IOCON_FUNC0 | IOCON_MODE_INACT },                                          // Status LED
00043     { IOCON_PIO1_7,  IOCON_FUNC1 | IOCON_HYS_EN | IOCON_MODE_PULLUP },                          // UART_TXD
00044 };
00045 
00046 
00047 void sysctlPowerDown(unsigned long powerdownmask)
00048 {
00049     unsigned long pdrun = LPC_SYSCTL->PDRUNCFG & PDRUNCFGMASKTMP;
00050     pdrun |= (powerdownmask & PDRUNCFGMASKTMP);
00051     LPC_SYSCTL->PDRUNCFG = pdrun | PDRUNCFGUSEMASK;
00052 }
00053 
00054 void sysctlPowerUp(unsigned long powerupmask)
00055 {
00056     unsigned long pdrun = LPC_SYSCTL->PDRUNCFG & PDRUNCFGMASKTMP;
00057     pdrun &= ~(powerupmask & PDRUNCFGMASKTMP);
00058     LPC_SYSCTL->PDRUNCFG = pdrun | PDRUNCFGUSEMASK;
00059 }
00060 
00061 void initWatchdog()
00062 {
00063     Chip_WWDT_Init(LPC_WWDT);                                   // Initialize watchdog
00064     sysctlPowerUp(SYSCTL_POWERDOWN_WDTOSC_PD);                  // Enable watchdog oscillator
00065     Chip_Clock_SetWDTOSC(WDTLFO_OSC_0_60 , 4);                   // WDT osc rate 0.6 MHz / 4 = 150 kHz
00066     Chip_Clock_SetWDTClockSource(SYSCTL_WDTCLKSRC_WDTOSC , 1);   // Clocking watchdog from its osc, div rate 1
00067     Chip_WWDT_SetTimeOut(LPC_WWDT, 37500);                      // 1 sec (hardcoded to reduce code size)
00068     Chip_WWDT_SetOption(LPC_WWDT, WWDT_WDMOD_WDRESET);          // Mode: reset on timeout
00069     Chip_WWDT_Start(LPC_WWDT);                                  // Go
00070 }
00071 
00072 void initClock()
00073 {
00074     sysctlPowerUp(SYSCTL_POWERDOWN_SYSOSC_PD);   // Enable system oscillator
00075     for (volatile int i = 0; i < 1000; i++) { }
00076 
00077     Chip_Clock_SetSystemPLLSource(SYSCTL_PLLCLKSRC_MAINOSC );
00078     sysctlPowerDown(SYSCTL_POWERDOWN_SYSPLL_PD);
00079 
00080     /*
00081      * Setup PLL for main oscillator rate (FCLKIN = 12MHz) * 4 = 48MHz
00082      * MSEL = 3 (this is pre-decremented), PSEL = 1 (for P = 2)
00083      * FCLKOUT = FCLKIN * (MSEL + 1) = 12MHz * 4 = 48MHz
00084      * FCCO = FCLKOUT * 2 * P = 48MHz * 2 * 2 = 192MHz (within FCCO range)
00085      */
00086     Chip_Clock_SetupSystemPLL(3, 1);
00087     sysctlPowerUp(SYSCTL_POWERDOWN_SYSPLL_PD);
00088     while (!Chip_Clock_IsSystemPLLLocked()) { }
00089 
00090     Chip_Clock_SetSysClockDiv(1);
00091 
00092     Chip_FMC_SetFLASHAccess(FLASHTIM_50MHZ_CPU );
00093 
00094     Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_PLLOUT );
00095 
00096     SystemCoreClock = Chip_Clock_GetSystemClockRate();
00097 
00098     while (SystemCoreClock != TargetSystemCoreClock) { }  // Loop forever if the clock failed to initialize properly
00099 }
00100 
00101 void initGpio()
00102 {
00103     LPC_SYSCTL->SYSAHBCLKCTRL |= 1 << SYSCTL_CLOCK_IOCON ;
00104     LPC_SYSCTL->SYSAHBCLKCTRL |= 1 << SYSCTL_CLOCK_GPIO ;
00105 
00106     for (unsigned i = 0; i < (sizeof(pinmux) / sizeof(PinMuxGroup)); i++)
00107     {
00108         LPC_IOCON->REG[pinmux[i].pin] = pinmux[i].modefunc;
00109     }
00110 
00111     LPC_GPIO[ErrorLedPort].DIR  |= 1 << ErrorLedPin;
00112     LPC_GPIO[StatusLedPort].DIR |= 1 << StatusLedPin;
00113 }
00114 
00115 void initUart()
00116 {
00117     Chip_UART_Init(LPC_USART);
00118     Chip_UART_SetBaud(LPC_USART, 115200);
00119     Chip_UART_TXEnable(LPC_USART);
00120 }
00121 
00122 void init()
00123 {
00124     Chip_SYSCTL_SetBODLevels(SYSCTL_BODRSTLVL_2_06V , SYSCTL_BODINTVAL_RESERVED1);
00125     Chip_SYSCTL_EnableBODReset();
00126 
00127     initWatchdog();
00128     initClock();
00129     initGpio();
00130     initUart();
00131 
00132     resetWatchdog();
00133 }
00134 
00135 } // namespace
00136 
00137 void die()
00138 {
00139     static const volatile unsigned& DHCSR = *reinterpret_cast<unsigned*>(0xE000EDF0U);
00140 
00141     syslog("FATAL\r\n");
00142 
00143     while (true)
00144     {
00145         if ((DHCSR & 1U) != 0)
00146         {
00147             __asm volatile ("bkpt #0\n");   // Break into the debugger
00148         }
00149     }
00150 }
00151 
00152 #if __GNUC__
00153 __attribute__((optimize(0)))     // Optimization must be disabled lest it hardfaults in the IAP call
00154 #endif
00155 void readUniqueID(std::uint8_t out_uid[UniqueIDSize])
00156 {
00157     unsigned aligned_array[5] = {};  // out_uid may be unaligned, so we need to use temp array
00158     unsigned iap_command = 58;
00159     reinterpret_cast<void(*)(void*, void*)>(0x1FFF1FF1)(&iap_command, aligned_array);
00160     std::memcpy(out_uid, &aligned_array[1], 16);
00161 }
00162 
00163 void setStatusLed(bool state)
00164 {
00165     LPC_GPIO[StatusLedPort].DATA[1 << StatusLedPin] = static_cast<unsigned long>(!state) << StatusLedPin;
00166 }
00167 
00168 void setErrorLed(bool state)
00169 {
00170     LPC_GPIO[ErrorLedPort].DATA[1 << ErrorLedPin] = static_cast<unsigned long>(!state) << ErrorLedPin;
00171 }
00172 
00173 void resetWatchdog()
00174 {
00175     Chip_WWDT_Feed(LPC_WWDT);
00176 }
00177 
00178 void syslog(const char* msg)
00179 {
00180     Chip_UART_SendBlocking(LPC_USART, msg, static_cast<int>(std::strlen(msg)));
00181 }
00182 
00183 } // namespace board
00184 
00185 extern "C"
00186 {
00187 
00188 void SystemInit();
00189 
00190 void SystemInit()
00191 {
00192     board::init();
00193 }
00194 
00195 }