Last active
July 6, 2016 06:04
-
-
Save monpetit/7f38cedb9d757dbfb7169b47f96ac85f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <inttypes.h> | |
#include "em_device.h" | |
#include "em_chip.h" | |
#include "em_usart.h" | |
#include "em_cmu.h" | |
#include "em_emu.h" | |
#include "em_int.h" | |
#include "em_timer.h" | |
#define LED_PIN (0) | |
#define LED_PORT (gpioPortA) | |
#define USART0_CS_PIN (13) | |
#define USART0_CS_PORT (gpioPortE) | |
#define LED_OFF() GPIO_PinOutSet(LED_PORT, LED_PIN) | |
#define LED_ON() GPIO_PinOutClear(LED_PORT, LED_PIN) | |
#define LED_TOGGLE() GPIO_PinOutToggle(LED_PORT, LED_PIN) | |
#define CS_HIGH() GPIO_PinOutSet(USART0_CS_PORT, USART0_CS_PIN) | |
#define CS_LOW() GPIO_PinOutClear(USART0_CS_PORT, USART0_CS_PIN) | |
static uint32_t system_count = 0; | |
volatile uint32_t systick_count = 0; | |
uint32_t clock_freq; | |
__STATIC_INLINE void __delay_tick(volatile uint32_t n); | |
__STATIC_INLINE uint32_t get_systick(void); | |
void __delay_ms(uint32_t milliseconds); | |
void setup_systick_timer(void); | |
void reset_blink(volatile uint8_t countdown); | |
void init_clocks(void); | |
void init_timer0(void); | |
void init_usart0(void); | |
void init_usart1(void); | |
void init_portio(void); | |
__STATIC_INLINE void uart1_putstr(uint8_t* buffer, size_t length); | |
char txbuffer[128]; | |
#define printf(...) do { \ | |
sprintf(txbuffer, __VA_ARGS__); \ | |
uart1_putstr((uint8_t*)txbuffer, strlen(txbuffer)); \ | |
} while (0) | |
#define putch(CH) USART_Tx(USART1, CH) | |
volatile uint8_t timer0_ready = 0; | |
__STATIC_INLINE uint8_t bcd2bin(uint8_t value) | |
{ | |
return ((value / 0x10) * 10 + value % 0x10); | |
} | |
__STATIC_INLINE uint8_t bin2bcd(uint8_t value) | |
{ | |
return (value / 10 * 0x10 + value % 10); | |
} | |
void set_datetime(uint16_t y, uint8_t mo, uint8_t d, uint8_t h, uint8_t mi, uint8_t s) | |
{ | |
uint8_t buf[8]; | |
buf[0] = 0x80; | |
buf[1] = bin2bcd(s); | |
buf[2] = bin2bcd(mi); | |
buf[3] = bin2bcd(h & 0x3f); | |
buf[5] = bin2bcd(d); | |
buf[6] = bin2bcd(mo & 0x1f); | |
buf[7] = bin2bcd((y - 2000) & 0xff); | |
CS_LOW(); | |
for (int i = 0; i < 8; i++) | |
USART_SpiTransfer(USART0, buf[i]); | |
CS_HIGH(); | |
} | |
void get_datetime(void) | |
{ | |
uint8_t buf[7]; | |
CS_LOW(); | |
USART_SpiTransfer(USART0, 0x00); | |
for (int i = 0; i < 7; i++) | |
buf[i] = USART_SpiTransfer(USART0, 0x00); | |
CS_HIGH(); | |
printf("%04d-%02d-%02d %02d:%02d:%02d\r\n", | |
bcd2bin(buf[6] & 0xff) + 2000, | |
bcd2bin(buf[5] & 0x1f), | |
bcd2bin(buf[4]), | |
bcd2bin(buf[2] & 0x3f), | |
bcd2bin(buf[1]), | |
bcd2bin(buf[0])); | |
} | |
/**************************************************************************//** | |
* @brief Main function | |
*****************************************************************************/ | |
int main(void) | |
{ | |
/* Chip errata */ | |
CHIP_Init(); | |
/* Enter default mode */ | |
init_clocks(); | |
init_usart0(); | |
init_usart1(); | |
init_portio(); | |
/* Ensure core frequency has been updated */ | |
SystemCoreClockUpdate(); | |
/* Start Systick Timer */ | |
setup_systick_timer(); | |
/* Setup TIMER0 */ | |
init_timer0(); | |
// set_datetime(2016, 7, 6, 12, 54, 30); | |
reset_blink(30); | |
__delay_ms(3000); | |
printf("\r\n**********************************\r\n"); | |
printf("*** EFM32 GECKO FIRMWARE START ***\r\n"); | |
printf("**********************************\r\n\r\n"); | |
/* Infinite loop */ | |
while (1) { | |
if (timer0_ready) { | |
timer0_ready = 0; | |
get_datetime(); | |
// printf("system tick = %u\r\n", get_systick()); | |
LED_ON(); | |
__delay_ms(20);; | |
LED_OFF(); | |
} | |
EMU_EnterEM1(); // CPU OFF | |
} | |
} | |
void SysTick_Handler(void) | |
{ | |
systick_count++; | |
} | |
__STATIC_INLINE uint32_t get_systick(void) | |
{ | |
return systick_count; | |
} | |
/****************************************************************************** | |
* @brief Delay function | |
*****************************************************************************/ | |
void __delay_ms(uint32_t milliseconds) | |
{ | |
uint32_t start_tick = get_systick(); | |
while ((get_systick() - start_tick) < milliseconds) { | |
} | |
} | |
void setup_systick_timer(void) | |
{ | |
clock_freq = CMU_ClockFreqGet(cmuClock_CORE); | |
/* Enable SysTick interrupt, necessary for __delay_ms() */ | |
if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1) ; | |
NVIC_EnableIRQ(SysTick_IRQn); | |
} | |
void reset_blink(volatile uint8_t countdown) | |
{ | |
while (countdown--) { | |
LED_TOGGLE(); | |
__delay_ms(20); | |
} | |
LED_OFF(); | |
} | |
void init_clocks(void) | |
{ | |
// $[HFXO] | |
CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOMODE_MASK) | CMU_CTRL_HFXOMODE_XTAL; | |
CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBOOST_MASK) | |
| CMU_CTRL_HFXOBOOST_50PCENT; | |
SystemHFXOClockSet(32000000); | |
// $[Use oscillator source] | |
CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_LFXOMODE_MASK) | CMU_CTRL_LFXOMODE_XTAL; | |
// [Use oscillator source]$ | |
// $[LFXO Boost Percent] | |
CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_LFXOBOOST_MASK) | |
| CMU_CTRL_LFXOBOOST_100PCENT; | |
// [LFXO Boost Percent]$ | |
// $[LFXO enable] | |
CMU_OscillatorEnable(cmuOsc_LFXO, true, true); | |
// [LFXO enable]$ | |
// $[HFXO enable] | |
CMU_OscillatorEnable(cmuOsc_HFXO, true, true); | |
// [HFXO enable]$ | |
// $[High Frequency Clock select] | |
/* Using HFXO as high frequency clock, HFCLK */ | |
CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); | |
/* Enable peripheral clock */ | |
CMU_ClockEnable(cmuClock_HFPER, true); | |
// [High Frequency Clock select]$ | |
// $[Peripheral Clock enables] | |
/* Enable clock for TIMER0 */ | |
CMU_ClockEnable(cmuClock_TIMER0, true); | |
/* Enable clock for USART0 */ | |
CMU_ClockEnable(cmuClock_USART0, true); | |
/* Enable clock for USART1 */ | |
CMU_ClockEnable(cmuClock_USART1, true); | |
/* Enable clock for GPIO by default */ | |
CMU_ClockEnable(cmuClock_GPIO, true); | |
// [Peripheral Clock enables]$ | |
} | |
/* SPI */ | |
void init_usart0(void) | |
{ | |
// $[USART_InitSync] | |
USART_InitSync_TypeDef initsync = USART_INITSYNC_DEFAULT; | |
initsync.baudrate = 1000000; | |
initsync.databits = usartDatabits8; | |
initsync.master = 1; | |
initsync.msbf = 1; | |
initsync.clockMode = usartClockMode3; | |
#if defined( USART_INPUT_RXPRS ) && defined( USART_TRIGCTRL_AUTOTXTEN ) | |
initsync.prsRxEnable = 0; | |
initsync.prsRxCh = 0; | |
initsync.autoTx = 0; | |
#endif | |
USART_InitSync(USART0, &initsync); | |
// [USART_InitSync]$ | |
} | |
/* UART */ | |
void init_usart1(void) | |
{ | |
// $[USART_InitAsync] | |
USART_InitAsync_TypeDef initasync = USART_INITASYNC_DEFAULT; | |
initasync.baudrate = 115200; | |
initasync.databits = usartDatabits8; | |
initasync.parity = usartNoParity; | |
initasync.stopbits = usartStopbits1; | |
initasync.oversampling = usartOVS16; | |
#if defined( USART_INPUT_RXPRS ) && defined( USART_CTRL_MVDIS ) | |
initasync.mvdis = 0; | |
initasync.prsRxEnable = 0; | |
initasync.prsRxCh = 0; | |
#endif | |
USART_InitAsync(USART1, &initasync); | |
// [USART_InitAsync]$ | |
} | |
void init_portio(void) | |
{ | |
// $[Port A Configuration] | |
/* Pin PA0 is configured to Push-pull */ | |
GPIO->P[0].MODEL = (GPIO->P[0].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) | |
| GPIO_P_MODEL_MODE0_PUSHPULL; | |
/* Pin PA1 is configured to Input enabled with pull-up */ | |
GPIO->P[0].DOUT |= (1 << 1); | |
GPIO->P[0].MODEL = (GPIO->P[0].MODEL & ~_GPIO_P_MODEL_MODE1_MASK) | |
| GPIO_P_MODEL_MODE1_INPUTPULL; | |
// [Port A Configuration]$ | |
// $[Port C Configuration] | |
/* Pin PC0 is configured to Push-pull */ | |
GPIO->P[2].MODEL = (GPIO->P[2].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) | |
| GPIO_P_MODEL_MODE0_PUSHPULL; | |
/* Pin PC1 is configured to Input enabled */ | |
GPIO->P[2].MODEL = (GPIO->P[2].MODEL & ~_GPIO_P_MODEL_MODE1_MASK) | |
| GPIO_P_MODEL_MODE1_INPUT; | |
// [Port C Configuration]$ | |
// $[Port E Configuration] | |
/* Pin PE10 is configured to Push-pull */ | |
GPIO->P[4].MODEH = (GPIO->P[4].MODEH & ~_GPIO_P_MODEH_MODE10_MASK) | |
| GPIO_P_MODEH_MODE10_PUSHPULL; | |
/* Pin PE11 is configured to Input enabled */ | |
GPIO->P[4].MODEH = (GPIO->P[4].MODEH & ~_GPIO_P_MODEH_MODE11_MASK) | |
| GPIO_P_MODEH_MODE11_INPUT; | |
/* Pin PE12 is configured to Push-pull */ | |
GPIO->P[4].MODEH = (GPIO->P[4].MODEH & ~_GPIO_P_MODEH_MODE12_MASK) | |
| GPIO_P_MODEH_MODE12_PUSHPULL; | |
/* Pin PE13 is configured to Push-pull */ | |
GPIO->P[4].DOUT |= (1 << 13); | |
GPIO->P[4].MODEH = (GPIO->P[4].MODEH & ~_GPIO_P_MODEH_MODE13_MASK) | |
| GPIO_P_MODEH_MODE13_PUSHPULL; | |
// [Port E Configuration]$ | |
// $[Route Configuration] | |
/* Enable signals CLK, RX, TX */ | |
USART0->ROUTE |= USART_ROUTE_CLKPEN | USART_ROUTE_RXPEN | USART_ROUTE_TXPEN; | |
/* Enable signals RX, TX */ | |
USART1->ROUTE |= USART_ROUTE_RXPEN | USART_ROUTE_TXPEN; | |
// [Route Configuration]$ | |
} | |
void init_timer0(void) | |
{ | |
// $[TIMER0 initialization] | |
TIMER_Init_TypeDef init = TIMER_INIT_DEFAULT; | |
init.enable = 1; | |
init.debugRun = 0; | |
init.dmaClrAct = 0; | |
init.sync = 0; | |
init.clkSel = timerClkSelHFPerClk; | |
init.prescale = timerPrescale1024; | |
init.fallAction = timerInputActionNone; | |
init.riseAction = timerInputActionNone; | |
init.mode = timerModeUp; | |
init.quadModeX4 = 0; | |
init.oneShot = 0; | |
TIMER_Init(TIMER0, &init); | |
// Enable TIMER0 overflow interrupt | |
TIMER_IntEnable(TIMER0, TIMER_IEN_OF); | |
TIMER_TopSet(TIMER0, (CMU_ClockFreqGet(cmuClock_CORE) / 1024) - 1); | |
NVIC_SetPriority(TIMER0_IRQn, 3); | |
NVIC_EnableIRQ(TIMER0_IRQn); | |
} | |
__STATIC_INLINE void uart1_putstr(uint8_t* buffer, size_t length) | |
{ | |
while (length--) { | |
putch(*buffer++); | |
} | |
} | |
void TIMER0_IRQHandler(void) | |
{ | |
TIMER_IntClear(TIMER0, TIMER_IF_OF); | |
timer0_ready = 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment