Initial commit

Add startup code for STM32L031K6, and blink two LEDs, one with CPU,
and one with the LPTIM at 60Hz for the (to-be-implemented) Sharp display.
This commit is contained in:
2019-02-23 17:32:07 -08:00
commit f69fbec0ae
53 changed files with 172045 additions and 0 deletions

175
test.c Normal file
View File

@@ -0,0 +1,175 @@
/**
Copyright 2019, Max Regan
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**/
#include <stdint.h>
#include "stm32l0xx.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
void SystemInit()
{
/**
* Use the MSI for the system clock, and disable all other clocks.
*/
/*!< Set MSION bit. Set by hardware to force the MSI oscillator ON
* when exiting from Stop or Standby mode, or in case of a failure
* of the HSE oscillator used directly or indirectly as system
* clock. This bit cannot be cleared if the MSI is used as system
* clock. */
RCC->CR |= RCC_CR_MSION;
RCC->ICSCR &= ~RCC_ICSCR_MSIRANGE;
RCC->ICSCR |= RCC_ICSCR_MSIRANGE_6; // | RCC_ICSCR_MSIRANGE_0;;
/*!< Reset
* SW[1:0] (use MSI oscillator as system clock),
* HPRE[3:0] (do not divide AHB clock in prescaler) ,
* PPRE1[2:0] (do not divide APB low-speed clock)
* PPRE2[2:0] (do not divide APB high-speed clock),
* MCOSEL[2:0] (disable MCO clock),
* MCOPRE[2:0] (disable MCO prescaler) */
RCC->CFGR &= ~RCC_CFGR_SW & ~RCC_CFGR_HPRE & ~RCC_CFGR_PPRE1 &
~RCC_CFGR_PPRE2 & ~RCC_CFGR_MCOSEL & ~RCC_CFGR_MCOPRE;
/*!< Reset
* HSION (disable HSI),
* HSIDIVEN (disable 18MHz HSI division)
* HSEON (disable HSE clock)
* CSSHSEON (disable HSE clock monitoring)
* PLLON (disable PLL)
*/
RCC->CR &= ~RCC_CR_HSION & ~RCC_CR_HSIDIVEN & ~RCC_CR_HSEON &
~RCC_CR_CSSHSEON & ~RCC_CR_PLLON;
/*!< Reset HSEBYP bit (disable HSE bypass) */
RCC->CR &= ~RCC_CR_HSEBYP;
/*!< Reset
* PLLSRC (HSI16 is the PLL source),
* PLLMUL[3:0] (3x PLL multiplication)
* Don't touch PLLDIV[1:0], since 0 is undefined
*/
RCC->CFGR &= ~RCC_CFGR_PLLSRC & ~RCC_CFGR_PLLMUL & ~RCC_CFGR_PLLDIV;
/* Enable APB1 for LPTIM */
RCC->APB1ENR |= RCC_APB1ENR_LPTIM1EN;
/*!< Disable all interrupts */
RCC->CIER = 0x00000000;
/* Configure the Vector Table location add offset address ------------------*/
SCB->VTOR = FLASH_BASE; /* Vector Table Relocation in Internal FLASH */
}
void init_lptim()
{
// Enable low-speed internal
RCC->CSR |= RCC_CSR_LSION;
while (!(RCC->CSR & RCC_CSR_LSIRDY)) {};
/*!< Set the LSI clock to be the source of the LPTIM */
RCC->CCIPR &= ~RCC_CCIPR_LPTIM1SEL;
RCC->CCIPR |= RCC_CCIPR_LPTIM1SEL_0;
/** Write CR CFGR and IER while LPTIM is disabled (LPTIM_CR_ENABLE not yet set) */
/*!< Disable Interrupts (not needed, this is the default */
LPTIM1->IER = 0;
/*!< Reset
* ENC (Disable encoder mode)
* TIMOUT (disable timeout mode)
* TRIGEN (Trigger count start with software only)
* PRELOAD (Update ARR and CMP registers immediately after write)
* CKSEL (LPTIM is using internal clock source)
* COUNTMODE (LPTIM counter updated on every clock pulse)
* TRGFLT (Do not debounce triggers)
*/
LPTIM1->CFGR &= ~LPTIM_CFGR_ENC & ~LPTIM_CFGR_TIMOUT & ~LPTIM_CFGR_TRIGEN &
~LPTIM_CFGR_TRIGSEL & ~LPTIM_CFGR_PRELOAD & ~LPTIM_CFGR_CKSEL &
~LPTIM_CFGR_COUNTMODE;
/*!< Set
* PRESC (Set prescaler to 128. Using 32kHz LSI as input, this should
* correspond to 250Hz counting.
*/
LPTIM1->CFGR &= LPTIM_CFGR_PRESC;
LPTIM1->CFGR |= 7u << LPTIM_CFGR_PRESC_Pos;
LPTIM1->CR |= LPTIM_CR_ENABLE;
/*!< Do not modify ARR and CMP until after ENABLE bit is set */
/*!< Produce a 60Hz, 50% duty cycle square wave. These values were
* determined experimentally. */
LPTIM1->ARR = 9;
LPTIM1->CMP = 4;
while(!(LPTIM1->ISR & LPTIM_ISR_ARROK)) {}
while(!(LPTIM1->ISR & LPTIM_ISR_CMPOK)) {}
/*!< Enable and start the timer */
LPTIM1->CR |= LPTIM_CR_CNTSTRT;
}
/*!< The buffer that will be used in the future to display on the watch display. */
static uint8_t display_buffer[144 * 168 / 8];
int main() {
/** Enable Port A,B clock */
RCC->IOPENR |= RCC_IOPENR_IOPAEN;
RCC->IOPENR |= RCC_IOPENR_IOPBEN;
/** Enable pin P3 for output */
GPIOB->MODER &= ~GPIO_MODER_MODE3;
GPIOB->MODER |= GPIO_MODER_MODE3_0;
GPIOB->OTYPER &= ~GPIO_OTYPER_OT_3;
GPIOB->PUPDR &= GPIO_PUPDR_PUPD3;
init_lptim();
/* Assign LPTIM1_OUT to PB3 (D13 on the Nucleo board) */
GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL7;
GPIOA->AFR[0] |= 1 << GPIO_AFRL_AFRL7_Pos;
GPIOA->MODER &= ~GPIO_MODER_MODE7;
GPIOA->MODER |= 2u << GPIO_MODER_MODE7_Pos; // Alternate Functionb
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_7;
GPIOA->PUPDR &= GPIO_PUPDR_PUPD7;
for ( uint32_t i = 0; i < ARRAY_SIZE(display_buffer); i++) {
display_buffer[i] = 0;
}
while (1) {
// #ifndef USE_PWM
for ( uint32_t i = 0; i < ARRAY_SIZE(display_buffer) - 1; i++) {
display_buffer[i] = display_buffer[i + 1] + 1;
}
for (uint32_t i = 0; i < 1000000; i++) {}
GPIOB->ODR ^= (GPIO_ODR_OD3);
// #endif
}
}