mirror of
https://github.com/google/pebble.git
synced 2025-07-06 23:26:21 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
93
platform/tintin/boot/src/drivers/stm32_common/button.c
Normal file
93
platform/tintin/boot/src/drivers/stm32_common/button.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "drivers/button.h"
|
||||
|
||||
#include "board/board.h"
|
||||
#include "drivers/periph_config.h"
|
||||
#include "drivers/gpio.h"
|
||||
|
||||
static void initialize_button_common(void) {
|
||||
if (!BOARD_CONFIG_BUTTON.button_com.gpio) {
|
||||
// This board doesn't use a button common pin.
|
||||
return;
|
||||
}
|
||||
|
||||
// Configure BUTTON_COM to drive low. When the button
|
||||
// is pressed this pin will be connected to the pin for the
|
||||
// button.
|
||||
gpio_use(BOARD_CONFIG_BUTTON.button_com.gpio);
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
GPIO_StructInit(&GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = BOARD_CONFIG_BUTTON.button_com.gpio_pin;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
GPIO_Init(BOARD_CONFIG_BUTTON.button_com.gpio, &GPIO_InitStructure);
|
||||
GPIO_WriteBit(BOARD_CONFIG_BUTTON.button_com.gpio, BOARD_CONFIG_BUTTON.button_com.gpio_pin, 0);
|
||||
|
||||
gpio_release(BOARD_CONFIG_BUTTON.button_com.gpio);
|
||||
}
|
||||
|
||||
static void initialize_button(const ButtonConfig* config) {
|
||||
// Configure the pin itself
|
||||
gpio_use(config->gpio);
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
GPIO_StructInit(&GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
GPIO_InitStructure.GPIO_Pin = config->gpio_pin;
|
||||
GPIO_Init(config->gpio, &GPIO_InitStructure);
|
||||
|
||||
gpio_release(config->gpio);
|
||||
}
|
||||
|
||||
bool button_is_pressed(ButtonId id) {
|
||||
const ButtonConfig* button_config = &BOARD_CONFIG_BUTTON.buttons[id];
|
||||
gpio_use(button_config->gpio);
|
||||
uint8_t bit = GPIO_ReadInputDataBit(button_config->gpio, button_config->gpio_pin);
|
||||
gpio_release(button_config->gpio);
|
||||
return !bit;
|
||||
}
|
||||
|
||||
uint8_t button_get_state_bits(void) {
|
||||
uint8_t button_state = 0x00;
|
||||
for (int i = 0; i < NUM_BUTTONS; ++i) {
|
||||
button_state |= (button_is_pressed(i) ? 0x01 : 0x00) << i;
|
||||
}
|
||||
return button_state;
|
||||
}
|
||||
|
||||
void button_init(void) {
|
||||
// Need to disable button wakeup functionality
|
||||
// or the buttons don't register input
|
||||
PWR_WakeUpPinCmd(DISABLE);
|
||||
|
||||
periph_config_enable(RCC_APB2PeriphClockCmd, RCC_APB2Periph_SYSCFG);
|
||||
|
||||
initialize_button_common();
|
||||
for (int i = 0; i < NUM_BUTTONS; ++i) {
|
||||
initialize_button(&BOARD_CONFIG_BUTTON.buttons[i]);
|
||||
}
|
||||
|
||||
periph_config_disable(RCC_APB2PeriphClockCmd, RCC_APB2Periph_SYSCFG);
|
||||
}
|
108
platform/tintin/boot/src/drivers/stm32_common/crc.c
Normal file
108
platform/tintin/boot/src/drivers/stm32_common/crc.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "drivers/crc.h"
|
||||
|
||||
#include "drivers/flash.h"
|
||||
#include "drivers/periph_config.h"
|
||||
|
||||
#include "stm32f2xx_crc.h"
|
||||
#include "stm32f2xx_rcc.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
static void prv_enable_crc_clock(void) {
|
||||
periph_config_enable(RCC_AHB1PeriphClockCmd, RCC_AHB1Periph_CRC);
|
||||
}
|
||||
|
||||
static void prv_disable_crc_clock(void) {
|
||||
periph_config_disable(RCC_AHB1PeriphClockCmd, RCC_AHB1Periph_CRC);
|
||||
}
|
||||
|
||||
static void prv_calculate_incremental_start(void) {
|
||||
prv_enable_crc_clock();
|
||||
CRC_ResetDR();
|
||||
}
|
||||
|
||||
static void prv_calculate_incremental_words(const uint32_t* data, unsigned int data_length) {
|
||||
CRC_CalcBlockCRC((uint32_t*) data, data_length);
|
||||
}
|
||||
|
||||
static uint32_t prv_calculate_incremental_remaining_bytes(const uint8_t* data,
|
||||
unsigned int data_length) {
|
||||
uint32_t crc_value;
|
||||
|
||||
if (data_length >= 4) {
|
||||
const unsigned int num_words = data_length / 4;
|
||||
prv_calculate_incremental_words((uint32_t*) data, num_words);
|
||||
|
||||
data += num_words * 4;
|
||||
data_length -= num_words * 4;
|
||||
}
|
||||
|
||||
if (data_length) {
|
||||
uint32_t last_word = 0;
|
||||
for (unsigned int i = 0; i < data_length; ++i) {
|
||||
last_word = (last_word << 8) | data[i];
|
||||
}
|
||||
crc_value = CRC_CalcCRC(last_word);
|
||||
} else {
|
||||
crc_value = CRC_GetCRC();
|
||||
}
|
||||
|
||||
return crc_value;
|
||||
}
|
||||
|
||||
static void prv_calculate_incremental_stop(void) {
|
||||
prv_disable_crc_clock();
|
||||
}
|
||||
|
||||
uint32_t crc_calculate_bytes(const uint8_t* data, unsigned int data_length) {
|
||||
prv_calculate_incremental_start();
|
||||
|
||||
// First calculate the CRC of the whole words, since the hardware works 4
|
||||
// bytes at a time.
|
||||
uint32_t* data_words = (uint32_t*) data;
|
||||
const unsigned int num_words = data_length / 4;
|
||||
prv_calculate_incremental_words(data_words, num_words);
|
||||
|
||||
const unsigned int num_remaining_bytes = data_length % 4;
|
||||
const uint32_t res =
|
||||
prv_calculate_incremental_remaining_bytes(data + (num_words * 4), num_remaining_bytes);
|
||||
prv_calculate_incremental_stop();
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
uint32_t crc_calculate_flash(uint32_t address, unsigned int num_bytes) {
|
||||
prv_calculate_incremental_start();
|
||||
const unsigned int chunk_size = 128;
|
||||
|
||||
uint8_t buffer[chunk_size];
|
||||
while (num_bytes > chunk_size) {
|
||||
flash_read_bytes(buffer, address, chunk_size);
|
||||
prv_calculate_incremental_words((const uint32_t*) buffer, chunk_size / 4);
|
||||
|
||||
num_bytes -= chunk_size;
|
||||
address += chunk_size;
|
||||
}
|
||||
|
||||
flash_read_bytes(buffer, address, num_bytes);
|
||||
const uint32_t res = prv_calculate_incremental_remaining_bytes(buffer, num_bytes);
|
||||
prv_calculate_incremental_stop();
|
||||
|
||||
return (res);
|
||||
}
|
107
platform/tintin/boot/src/drivers/stm32_common/dbgserial.c
Normal file
107
platform/tintin/boot/src/drivers/stm32_common/dbgserial.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "drivers/dbgserial.h"
|
||||
|
||||
#include "drivers/periph_config.h"
|
||||
|
||||
#include "drivers/gpio.h"
|
||||
|
||||
#include "stm32f2xx_rcc.h"
|
||||
#include "stm32f2xx_gpio.h"
|
||||
#include "stm32f2xx_usart.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const int SERIAL_BAUD_RATE = 230400;
|
||||
|
||||
void dbgserial_init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
USART_InitTypeDef USART_InitStructure;
|
||||
|
||||
// Enable GPIO and UART3 peripheral clocks
|
||||
gpio_use(GPIOC);
|
||||
periph_config_enable(RCC_APB1PeriphClockCmd, RCC_APB1Periph_USART3);
|
||||
|
||||
// USART_OverSampling8Cmd(USART3, ENABLE);
|
||||
|
||||
/* Connect PXx to USARTx_Tx*/
|
||||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
|
||||
|
||||
/* Connect PXx to USARTx_Rx*/
|
||||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);
|
||||
|
||||
/* Configure USART Tx as alternate function */
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
|
||||
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
||||
|
||||
/* Configure USART Rx as alternate function */
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
|
||||
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
||||
|
||||
/* USART configuration */
|
||||
USART_InitStructure.USART_BaudRate = SERIAL_BAUD_RATE;
|
||||
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
|
||||
USART_Init(USART3, &USART_InitStructure);
|
||||
|
||||
/* Enable USART */
|
||||
USART_Cmd(USART3, ENABLE);
|
||||
|
||||
gpio_release(GPIOC);
|
||||
}
|
||||
|
||||
static void prv_putchar(uint8_t c) {
|
||||
while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET) continue;
|
||||
USART_SendData(USART3, c);
|
||||
while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET) continue;
|
||||
}
|
||||
|
||||
void dbgserial_print(const char* str) {
|
||||
while (*str) {
|
||||
prv_putchar(*str);
|
||||
++str;
|
||||
}
|
||||
}
|
||||
|
||||
void dbgserial_newline(void) {
|
||||
prv_putchar('\r');
|
||||
prv_putchar('\n');
|
||||
}
|
||||
|
||||
void dbgserial_putstr(const char* str) {
|
||||
dbgserial_print(str);
|
||||
|
||||
dbgserial_newline();
|
||||
}
|
||||
|
||||
void dbgserial_print_hex(uint32_t value) {
|
||||
char buf[12];
|
||||
itoa(value, buf, sizeof(buf));
|
||||
dbgserial_print(buf);
|
||||
}
|
38
platform/tintin/boot/src/drivers/stm32_common/gpio.c
Normal file
38
platform/tintin/boot/src/drivers/stm32_common/gpio.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "drivers/gpio.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_GPIO (9)
|
||||
|
||||
|
||||
static uint32_t s_gpio_clock_count[MAX_GPIO];
|
||||
|
||||
void gpio_use(GPIO_TypeDef* GPIOx) {
|
||||
uint32_t idx = ((((uint32_t)GPIOx) - AHB1PERIPH_BASE) / 0x0400);
|
||||
if ((idx < MAX_GPIO) && !(s_gpio_clock_count[idx]++)) {
|
||||
SET_BIT(RCC->AHB1ENR, (0x1 << idx));
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_release(GPIO_TypeDef* GPIOx) {
|
||||
uint32_t idx = ((((uint32_t)GPIOx) - AHB1PERIPH_BASE) / 0x0400);
|
||||
if ((idx < MAX_GPIO) && s_gpio_clock_count[idx] && !(--s_gpio_clock_count[idx])) {
|
||||
CLEAR_BIT(RCC->AHB1ENR, (0x1 << idx));
|
||||
}
|
||||
}
|
39
platform/tintin/boot/src/drivers/stm32_common/otp.c
Normal file
39
platform/tintin/boot/src/drivers/stm32_common/otp.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "drivers/otp.h"
|
||||
|
||||
#include "stm32f2xx_flash.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// See page 53 of STM Reference Manual RM0033:
|
||||
#define OTP_SLOTS_BASE_ADDR (0x1FFF7800)
|
||||
#define OTP_LOCKS_BASE_ADDR (0x1FFF7A00)
|
||||
|
||||
//! Each OTP slot is 32 bytes. There are 16 slots: [0-15]
|
||||
char * otp_get_slot(const uint8_t index) {
|
||||
return (char * const) (OTP_SLOTS_BASE_ADDR + (32 * index));
|
||||
}
|
||||
|
||||
uint8_t * otp_get_lock(const uint8_t index) {
|
||||
return (uint8_t * const) (OTP_LOCKS_BASE_ADDR + index);
|
||||
}
|
||||
|
||||
bool otp_is_locked(const uint8_t index) {
|
||||
return (*otp_get_lock(index) == 0);
|
||||
}
|
219
platform/tintin/boot/src/drivers/stm32_common/rtc.c
Normal file
219
platform/tintin/boot/src/drivers/stm32_common/rtc.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "drivers/dbgserial.h"
|
||||
#include "drivers/periph_config.h"
|
||||
#include "drivers/rtc.h"
|
||||
#include "util/delay.h"
|
||||
#include "system/rtc_registers.h"
|
||||
|
||||
#include "stm32f2xx_rcc.h"
|
||||
#include "stm32f2xx_rtc.h"
|
||||
|
||||
//! LSE startup time, about 4 seconds empirically,
|
||||
//! but we give it 30 seconds since it it fails we sadwatch
|
||||
static const int LSE_READY_TIMEOUT_MS = 30000;
|
||||
static const unsigned int LSE_FREQUENCY_HZ = 32768;
|
||||
static const int RTC_ASYNC_PRESCALER = 7;
|
||||
static const int RTC_SYNC_PRESCALER = 3;
|
||||
|
||||
static const unsigned int RTC_TICKS_HZ = 1024;
|
||||
static const unsigned int TICKS_IN_INTERVAL = 60 * 60 * 24;
|
||||
|
||||
static uint32_t prv_get_asynchronous_prescaler(void) {
|
||||
return (RTC->PRER >> 16) & 0x7f;
|
||||
}
|
||||
|
||||
static uint32_t prv_get_synchronous_prescaler(void) {
|
||||
return RTC->PRER & 0x1fff;
|
||||
}
|
||||
|
||||
//! Are we in slow mode?
|
||||
static bool prv_slow_mode() {
|
||||
return prv_get_asynchronous_prescaler() == 0x7f && prv_get_synchronous_prescaler() == 0xff;
|
||||
}
|
||||
|
||||
static bool prv_clocksource_is_lse_started(void) {
|
||||
return RCC_GetFlagStatus(RCC_FLAG_LSERDY) != RESET;
|
||||
}
|
||||
|
||||
static bool prv_clocksource_lse_configure(void) {
|
||||
if (prv_clocksource_is_lse_started()) {
|
||||
// LSE remains on through standby and resets so often don't need to do anything
|
||||
return true;
|
||||
}
|
||||
|
||||
dbgserial_putstr("Starting LSE oscillator");
|
||||
RCC_LSEConfig(RCC_LSE_ON);
|
||||
for (int i = 0; i < LSE_READY_TIMEOUT_MS; i++) {
|
||||
if (prv_clocksource_is_lse_started()) {
|
||||
return true;
|
||||
}
|
||||
delay_us(1000);
|
||||
}
|
||||
|
||||
dbgserial_putstr("LSE oscillator did not start");
|
||||
return false;
|
||||
}
|
||||
|
||||
//! This routine relies on bootbits already having enabled
|
||||
//! access to the PWR clock and backup domain. Re-enabling
|
||||
//! it here breaks wakeup for some reason
|
||||
//! Returns false if configuring LSE failed
|
||||
bool rtc_init(void) {
|
||||
if (!prv_clocksource_lse_configure()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
|
||||
RCC_RTCCLKCmd(ENABLE);
|
||||
RTC_WaitForSynchro();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Before entering standby we set the RTC to it's default time (Jan 1, 2000)
|
||||
// here we calculate the seconds elapsed since then
|
||||
static int32_t prv_seconds_since_standby(void) {
|
||||
// This function assumes the RTC is running in slow mode
|
||||
|
||||
RTC_TimeTypeDef rtc_time;
|
||||
RTC_GetTime(RTC_Format_BIN, &rtc_time);
|
||||
|
||||
RTC_DateTypeDef rtc_date;
|
||||
RTC_GetDate(RTC_Format_BIN, &rtc_date);
|
||||
|
||||
// Unlike mktime there's no error checking here since if something goes wrong
|
||||
// it'll just give us the wrong time anyway
|
||||
|
||||
unsigned days = rtc_date.RTC_Year * 365; // RTC_Year is 0-99
|
||||
days += (rtc_date.RTC_Year / 4); // Leap years
|
||||
|
||||
// Cumulative days from previous months
|
||||
const unsigned month_days[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
|
||||
|
||||
days += month_days[rtc_date.RTC_Month - 1 ]; // RTC_Month is 1-12
|
||||
if ((rtc_date.RTC_Year + 1) % 4 == 0 && rtc_date.RTC_Month > 2) {
|
||||
// On a leap year and past February so add a leap day.
|
||||
days++;
|
||||
}
|
||||
|
||||
// Add in previous days of the current month
|
||||
days += rtc_date.RTC_Date - 1;
|
||||
|
||||
return rtc_time.RTC_Seconds + 60 * (rtc_time.RTC_Minutes + 60 *
|
||||
(rtc_time.RTC_Hours + 24 * days));
|
||||
}
|
||||
|
||||
void rtc_initialize_fast_mode(void) {
|
||||
// We configure the RTC to run in "fast time". This means that the calendar will
|
||||
// be completely wrong, as we're incrementing the second count many times for every
|
||||
// real second. The firmware's driver will hide this fact from the rest of the
|
||||
// system. The reason we're doing this is because the STM32F2 micro doesn't offer
|
||||
// a subsecond field in their calendar, so we resort to crazy workarounds to get
|
||||
// a higher resolution timer.
|
||||
RTC_InitTypeDef rtc_init_struct;
|
||||
RTC_StructInit(&rtc_init_struct);
|
||||
|
||||
_Static_assert((LSE_FREQUENCY_HZ / ((RTC_ASYNC_PRESCALER + 1) * (RTC_SYNC_PRESCALER + 1))) ==
|
||||
RTC_TICKS_HZ, "Our prescalers won't create the clock we want");
|
||||
_Static_assert(RTC_ASYNC_PRESCALER >= 6, "PREDIV_A < 6 - Coarse calibration will not work.");
|
||||
|
||||
rtc_init_struct.RTC_AsynchPrediv = RTC_ASYNC_PRESCALER;
|
||||
rtc_init_struct.RTC_SynchPrediv = RTC_SYNC_PRESCALER;
|
||||
|
||||
RTC_Init(&rtc_init_struct);
|
||||
|
||||
// Reset RTC time to 0, fast mode doesn't use the date register so leave it alone
|
||||
RTC_TimeTypeDef rtc_time;
|
||||
RTC_TimeStructInit(&rtc_time);
|
||||
RTC_SetTime(RTC_Format_BIN, &rtc_time);
|
||||
}
|
||||
|
||||
void rtc_speed_up(void) {
|
||||
if (!prv_slow_mode()) {
|
||||
// If we're not in slow mode there's nothing to do
|
||||
return;
|
||||
}
|
||||
// On standby the RTC is reset to date 0, so the RTC's time is really
|
||||
// the number of seconds we've been in standby
|
||||
int32_t elapsed_since_standby = prv_seconds_since_standby();
|
||||
|
||||
int32_t saved_time = RTC_ReadBackupRegister(CURRENT_TIME_REGISTER);
|
||||
// Correct the saved time with the number of seconds we've been in standby mode
|
||||
saved_time += elapsed_since_standby;
|
||||
|
||||
// Save time in the backup register so the firmware can read it once it boots
|
||||
RTC_WriteBackupRegister(CURRENT_TIME_REGISTER, saved_time);
|
||||
RTC_WriteBackupRegister(CURRENT_INTERVAL_TICKS_REGISTER, 0);
|
||||
|
||||
rtc_initialize_fast_mode();
|
||||
}
|
||||
|
||||
static uint32_t prv_bcd_to_byte(uint32_t value) {
|
||||
const uint32_t tmp = ((value & 0xF0) >> 0x4) * 10;
|
||||
return (tmp + (value & 0x0F));
|
||||
}
|
||||
|
||||
static uint32_t prv_cur_ticks(void) {
|
||||
uint32_t time_register = RTC->TR;
|
||||
|
||||
const uint32_t hours = prv_bcd_to_byte((time_register & (RTC_TR_HT | RTC_TR_HU)) >> 16);
|
||||
const uint32_t minutes = prv_bcd_to_byte((time_register & (RTC_TR_MNT | RTC_TR_MNU)) >> 8);
|
||||
const uint32_t seconds = prv_bcd_to_byte(time_register & (RTC_TR_ST | RTC_TR_SU));
|
||||
|
||||
return (((hours * 60) + minutes) * 60) + seconds;
|
||||
}
|
||||
|
||||
static uint32_t prv_elapsed_ticks(uint32_t before, uint32_t after) {
|
||||
int32_t result = after - before;
|
||||
if (result < 0) {
|
||||
result = (TICKS_IN_INTERVAL - before) + after;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void rtc_slow_down(void) {
|
||||
if (prv_slow_mode()) {
|
||||
// If we're already slowed down there is nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the current time and then save it back into the backup register
|
||||
int32_t last_save_time = RTC_ReadBackupRegister(CURRENT_TIME_REGISTER);
|
||||
uint32_t last_save_ticks = RTC_ReadBackupRegister(CURRENT_INTERVAL_TICKS_REGISTER);
|
||||
uint32_t ticks_since_save = prv_elapsed_ticks(last_save_ticks, prv_cur_ticks());
|
||||
|
||||
int32_t cur_time = last_save_time + ticks_since_save / RTC_TICKS_HZ;
|
||||
// Save the current time into the backup registers
|
||||
RTC_WriteBackupRegister(CURRENT_TIME_REGISTER, cur_time);
|
||||
|
||||
// Set the RTC back to defaults (normal prescalers)
|
||||
RTC_InitTypeDef rtc_init_struct;
|
||||
RTC_StructInit(&rtc_init_struct);
|
||||
RTC_Init(&rtc_init_struct);
|
||||
|
||||
// Set the RTC to default date and time.
|
||||
// When we speed up the clock we'll add the elapsed seconds
|
||||
// to the saved register to get the correct time
|
||||
RTC_TimeTypeDef rtc_default_time;
|
||||
RTC_TimeStructInit(&rtc_default_time);
|
||||
RTC_SetTime(RTC_Format_BIN, &rtc_default_time);
|
||||
RTC_DateTypeDef rtc_default_date;
|
||||
RTC_DateStructInit(&rtc_default_date);
|
||||
RTC_SetDate(RTC_Format_BIN, &rtc_default_date);
|
||||
}
|
109
platform/tintin/boot/src/drivers/stm32_common/system_flash.c
Normal file
109
platform/tintin/boot/src/drivers/stm32_common/system_flash.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "drivers/system_flash.h"
|
||||
|
||||
#include "drivers/dbgserial.h"
|
||||
#include "util/misc.h"
|
||||
|
||||
#include "stm32f2xx_flash.h"
|
||||
|
||||
static uint16_t s_sectors[] = {
|
||||
FLASH_Sector_0, FLASH_Sector_1, FLASH_Sector_2, FLASH_Sector_3,
|
||||
FLASH_Sector_4, FLASH_Sector_5, FLASH_Sector_6, FLASH_Sector_7
|
||||
};
|
||||
static uint32_t s_sector_addresses[] = {
|
||||
ADDR_FLASH_SECTOR_0, ADDR_FLASH_SECTOR_1, ADDR_FLASH_SECTOR_2, ADDR_FLASH_SECTOR_3,
|
||||
ADDR_FLASH_SECTOR_4, ADDR_FLASH_SECTOR_5, ADDR_FLASH_SECTOR_6, ADDR_FLASH_SECTOR_7
|
||||
};
|
||||
|
||||
int prv_get_sector_num_for_address(uint32_t address) {
|
||||
if (address < s_sector_addresses[0]) {
|
||||
dbgserial_print("address ");
|
||||
dbgserial_print_hex(address);
|
||||
dbgserial_putstr(" is outside system flash");
|
||||
return -1;
|
||||
}
|
||||
for (size_t i=0; i < ARRAY_LENGTH(s_sector_addresses)-1; ++i) {
|
||||
if (s_sector_addresses[i] <= address
|
||||
&& address < s_sector_addresses[i+1]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return ARRAY_LENGTH(s_sector_addresses)-1;
|
||||
}
|
||||
|
||||
bool system_flash_erase(
|
||||
uint32_t address, size_t length,
|
||||
SystemFlashProgressCb progress_callback, void *progress_context) {
|
||||
if (length == 0) {
|
||||
// Nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
int first_sector = prv_get_sector_num_for_address(address);
|
||||
int last_sector = prv_get_sector_num_for_address(address + length - 1);
|
||||
if (first_sector < 0 || last_sector < 0) {
|
||||
return false;
|
||||
}
|
||||
int count = last_sector - first_sector + 1;
|
||||
if (progress_callback) {
|
||||
progress_callback(0, count, progress_context);
|
||||
}
|
||||
|
||||
FLASH_Unlock();
|
||||
for (int sector = first_sector; sector <= last_sector; ++sector) {
|
||||
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
|
||||
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
|
||||
if (FLASH_EraseSector(
|
||||
s_sectors[sector], VoltageRange_1) != FLASH_COMPLETE) {
|
||||
dbgserial_print("failed to erase sector ");
|
||||
dbgserial_print_hex(sector);
|
||||
dbgserial_newline();
|
||||
FLASH_Lock();
|
||||
return false;
|
||||
}
|
||||
if (progress_callback) {
|
||||
progress_callback(sector - first_sector + 1, count, progress_context);
|
||||
}
|
||||
}
|
||||
FLASH_Lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool system_flash_write(
|
||||
uint32_t address, const void *data, size_t length,
|
||||
SystemFlashProgressCb progress_callback, void *progress_context) {
|
||||
FLASH_Unlock();
|
||||
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
|
||||
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
|
||||
|
||||
const uint8_t *data_array = data;
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
if (FLASH_ProgramByte(address + i, data_array[i]) != FLASH_COMPLETE) {
|
||||
dbgserial_print("failed to write address ");
|
||||
dbgserial_print_hex(address);
|
||||
dbgserial_newline();
|
||||
FLASH_Lock();
|
||||
return false;
|
||||
}
|
||||
if (progress_callback && i % 128 == 0) {
|
||||
progress_callback(i/128, length/128, progress_context);
|
||||
}
|
||||
}
|
||||
FLASH_Lock();
|
||||
return true;
|
||||
}
|
41
platform/tintin/boot/src/drivers/stm32_common/watchdog.c
Normal file
41
platform/tintin/boot/src/drivers/stm32_common/watchdog.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "drivers/watchdog.h"
|
||||
|
||||
#include "stm32f2xx_dbgmcu.h"
|
||||
#include "stm32f2xx_iwdg.h"
|
||||
#include "stm32f2xx_rcc.h"
|
||||
|
||||
void watchdog_init(void) {
|
||||
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
|
||||
|
||||
IWDG_SetPrescaler(IWDG_Prescaler_64); // ~8 seconds
|
||||
IWDG_SetReload(0xfff);
|
||||
|
||||
IWDG_WriteAccessCmd(IWDG_WriteAccess_Disable);
|
||||
|
||||
DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP, ENABLE);
|
||||
}
|
||||
|
||||
void watchdog_start(void) {
|
||||
IWDG_Enable();
|
||||
IWDG_ReloadCounter();
|
||||
}
|
||||
|
||||
bool watchdog_check_reset_flag(void) {
|
||||
return RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue