mirror of
https://github.com/google/pebble.git
synced 2025-11-24 00:10:56 -05:00
Import of the watch repository from Pebble
This commit is contained in:
427
src/fw/board/boards/board_silk.c
Normal file
427
src/fw/board/boards/board_silk.c
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* 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 "board/board.h"
|
||||
|
||||
#include "drivers/exti.h"
|
||||
#include "drivers/flash/qspi_flash_definitions.h"
|
||||
#include "drivers/i2c_definitions.h"
|
||||
#include "drivers/qspi_definitions.h"
|
||||
#include "drivers/stm32f2/dma_definitions.h"
|
||||
#include "drivers/stm32f2/i2c_hal_definitions.h"
|
||||
#include "drivers/stm32f2/spi_definitions.h"
|
||||
#include "drivers/stm32f2/uart_definitions.h"
|
||||
#include "drivers/temperature.h"
|
||||
#include "drivers/voltage_monitor.h"
|
||||
#include "flash_region/flash_region.h"
|
||||
#include "util/units.h"
|
||||
|
||||
#define DIALOG_SPI_DMA_PRIORITY (0x0b)
|
||||
// Make sure that the DMA IRQ is handled before EXTI:
|
||||
// See comments in host/host_transport.c prv_int_exti_cb()
|
||||
_Static_assert(DIALOG_SPI_DMA_PRIORITY < EXTI_PRIORITY, "Dialog SPI DMA priority too low!");
|
||||
|
||||
// DMA Controllers
|
||||
|
||||
static DMAControllerState s_dma1_state;
|
||||
static DMAController DMA1_DEVICE = {
|
||||
.state = &s_dma1_state,
|
||||
.periph = DMA1,
|
||||
.rcc_bit = RCC_AHB1Periph_DMA1,
|
||||
};
|
||||
|
||||
static DMAControllerState s_dma2_state;
|
||||
static DMAController DMA2_DEVICE = {
|
||||
.state = &s_dma2_state,
|
||||
.periph = DMA2,
|
||||
.rcc_bit = RCC_AHB1Periph_DMA2,
|
||||
};
|
||||
|
||||
// DMA Streams
|
||||
|
||||
CREATE_DMA_STREAM(1, 4); // DMA2_STREAM2_DEVICE - Sharp SPI TX
|
||||
CREATE_DMA_STREAM(2, 1); // DMA1_STREAM2_DEVICE - Accessory UART RX
|
||||
CREATE_DMA_STREAM(2, 2); // DMA1_STREAM1_DEVICE - Debug UART RX
|
||||
CREATE_DMA_STREAM(2, 3); // DMA2_STREAM0_DEVICE - Dialog SPI RX
|
||||
CREATE_DMA_STREAM(2, 5); // DMA2_STREAM1_DEVICE - Dialog SPI TX
|
||||
CREATE_DMA_STREAM(2, 6); // DMA2_STREAM4_DEVICE - DFSDM
|
||||
CREATE_DMA_STREAM(2, 7); // DMA2_STREAM7_DEVICE - QSPI
|
||||
|
||||
// DMA Requests
|
||||
// - On DMA1 we just have have "Sharp SPI TX" so just set its priority to "High" since it doesn't
|
||||
// matter.
|
||||
// - On DMA2 we have "Accessory UART RX", "Debug UART RX", "Dialog SPI RX", "DIALOG SPI TX",
|
||||
// "DFSDM", and "QSPI". We want "DFSDM", "Accessory UART RX", "Debug UART RX", and "Dialog SPI RX"
|
||||
// to have a very high priority because their peripheral buffers may overflow if the DMA stream
|
||||
// doesn't read from them in a while. After that, give the remaining "Dialog SPI TX" and "QSPI"
|
||||
// both a high priority.
|
||||
|
||||
static DMARequestState s_sharp_spi_tx_dma_request_state;
|
||||
static DMARequest SHARP_SPI_TX_DMA_REQUEST = {
|
||||
.state = &s_sharp_spi_tx_dma_request_state,
|
||||
.stream = &DMA1_STREAM4_DEVICE,
|
||||
.channel = 0,
|
||||
.irq_priority = 0x0f,
|
||||
.priority = DMARequestPriority_High,
|
||||
.type = DMARequestType_MemoryToPeripheral,
|
||||
.data_size = DMARequestDataSize_Byte,
|
||||
};
|
||||
DMARequest * const SHARP_SPI_TX_DMA = &SHARP_SPI_TX_DMA_REQUEST;
|
||||
|
||||
static DMARequestState s_accessory_uart_dma_request_state;
|
||||
static DMARequest ACCESSORY_UART_RX_DMA_REQUEST = {
|
||||
.state = &s_accessory_uart_dma_request_state,
|
||||
.stream = &DMA2_STREAM1_DEVICE,
|
||||
.channel = 5,
|
||||
.irq_priority = IRQ_PRIORITY_INVALID, // no interrupts
|
||||
.priority = DMARequestPriority_VeryHigh,
|
||||
.type = DMARequestType_PeripheralToMemory,
|
||||
.data_size = DMARequestDataSize_Byte,
|
||||
};
|
||||
|
||||
static DMARequestState s_dbg_uart_dma_request_state;
|
||||
static DMARequest DBG_UART_RX_DMA_REQUEST = {
|
||||
.state = &s_dbg_uart_dma_request_state,
|
||||
.stream = &DMA2_STREAM2_DEVICE,
|
||||
.channel = 4,
|
||||
.irq_priority = IRQ_PRIORITY_INVALID, // no interrupts
|
||||
.priority = DMARequestPriority_VeryHigh,
|
||||
.type = DMARequestType_PeripheralToMemory,
|
||||
.data_size = DMARequestDataSize_Byte,
|
||||
};
|
||||
|
||||
static DMARequestState s_dialog_spi_rx_dma_request_state;
|
||||
static DMARequest DIALOG_SPI_RX_DMA_REQUEST = {
|
||||
.state = &s_dialog_spi_rx_dma_request_state,
|
||||
.stream = &DMA2_STREAM3_DEVICE,
|
||||
.channel = 2,
|
||||
.irq_priority = DIALOG_SPI_DMA_PRIORITY,
|
||||
.priority = DMARequestPriority_VeryHigh,
|
||||
.type = DMARequestType_PeripheralToMemory,
|
||||
.data_size = DMARequestDataSize_Byte,
|
||||
};
|
||||
|
||||
static DMARequestState s_dialog_spi_tx_dma_request_state;
|
||||
static DMARequest DIALOG_SPI_TX_DMA_REQUEST = {
|
||||
.state = &s_dialog_spi_tx_dma_request_state,
|
||||
.stream = &DMA2_STREAM5_DEVICE,
|
||||
.channel = 5,
|
||||
.irq_priority = DIALOG_SPI_DMA_PRIORITY,
|
||||
.priority = DMARequestPriority_High,
|
||||
.type = DMARequestType_MemoryToPeripheral,
|
||||
.data_size = DMARequestDataSize_Byte,
|
||||
};
|
||||
|
||||
static DMARequestState s_dfsdm_dma_request_state;
|
||||
static DMARequest DFSDM_DMA_REQUEST = {
|
||||
.state = &s_dfsdm_dma_request_state,
|
||||
.stream = &DMA2_STREAM6_DEVICE,
|
||||
.channel = 3,
|
||||
.irq_priority = 0x0f,
|
||||
.priority = DMARequestPriority_VeryHigh,
|
||||
.type = DMARequestType_PeripheralToMemory,
|
||||
.data_size = DMARequestDataSize_Word,
|
||||
};
|
||||
|
||||
static DMARequestState s_qspi_dma_request_state;
|
||||
static DMARequest QSPI_DMA_REQUEST = {
|
||||
.state = &s_qspi_dma_request_state,
|
||||
.stream = &DMA2_STREAM7_DEVICE,
|
||||
.channel = 3,
|
||||
.irq_priority = 0x0f,
|
||||
.priority = DMARequestPriority_High,
|
||||
.type = DMARequestType_PeripheralToMemory,
|
||||
.data_size = DMARequestDataSize_Word,
|
||||
};
|
||||
|
||||
|
||||
// UART DEVICES
|
||||
|
||||
static UARTDeviceState s_bt_bootrom_rx_uart_state;
|
||||
static UARTDevice BT_RX_BOOTROM_UART_DEVICE = {
|
||||
.state = &s_bt_bootrom_rx_uart_state,
|
||||
.periph = USART6,
|
||||
.rx_gpio = { GPIOA, GPIO_Pin_12, GPIO_PinSource12, GPIO_AF_USART6 },
|
||||
.rcc_apb_periph = RCC_APB2Periph_USART6,
|
||||
.tx_gpio = { 0 }
|
||||
};
|
||||
|
||||
static UARTDeviceState s_bt_bootrom_tx_uart_state;
|
||||
static UARTDevice BT_TX_BOOTROM_UART_DEVICE = {
|
||||
.state = &s_bt_bootrom_tx_uart_state,
|
||||
.periph = USART2,
|
||||
.tx_gpio = { GPIOA, GPIO_Pin_2, GPIO_PinSource2, GPIO_AF_USART2 },
|
||||
.rcc_apb_periph = RCC_APB1Periph_USART2,
|
||||
.rx_gpio = { 0 }
|
||||
};
|
||||
|
||||
UARTDevice * const BT_TX_BOOTROM_UART = &BT_TX_BOOTROM_UART_DEVICE;
|
||||
UARTDevice * const BT_RX_BOOTROM_UART = &BT_RX_BOOTROM_UART_DEVICE;
|
||||
|
||||
#if TARGET_QEMU
|
||||
static UARTDeviceState s_qemu_uart_state;
|
||||
static UARTDevice QEMU_UART_DEVICE = {
|
||||
.state = &s_qemu_uart_state,
|
||||
// GPIO? Where we're going, we don't need GPIO. (connected to QEMU)
|
||||
.periph = USART2,
|
||||
.irq_channel = USART2_IRQn,
|
||||
.irq_priority = 13,
|
||||
.rcc_apb_periph = RCC_APB1Periph_USART2
|
||||
};
|
||||
UARTDevice * const QEMU_UART = &QEMU_UART_DEVICE;
|
||||
IRQ_MAP(USART2, uart_irq_handler, QEMU_UART);
|
||||
#endif
|
||||
|
||||
static UARTDeviceState s_dbg_uart_state;
|
||||
static UARTDevice DBG_UART_DEVICE = {
|
||||
.state = &s_dbg_uart_state,
|
||||
.tx_gpio = {
|
||||
.gpio = GPIOA,
|
||||
.gpio_pin = GPIO_Pin_9,
|
||||
.gpio_pin_source = GPIO_PinSource9,
|
||||
.gpio_af = GPIO_AF_USART1
|
||||
},
|
||||
.rx_gpio = {
|
||||
.gpio = GPIOB,
|
||||
.gpio_pin = GPIO_Pin_7,
|
||||
.gpio_pin_source = GPIO_PinSource7,
|
||||
.gpio_af = GPIO_AF_USART1
|
||||
},
|
||||
.periph = USART1,
|
||||
.irq_channel = USART1_IRQn,
|
||||
.irq_priority = 13,
|
||||
.rcc_apb_periph = RCC_APB2Periph_USART1,
|
||||
.rx_dma = &DBG_UART_RX_DMA_REQUEST
|
||||
};
|
||||
UARTDevice * const DBG_UART = &DBG_UART_DEVICE;
|
||||
IRQ_MAP(USART1, uart_irq_handler, DBG_UART);
|
||||
|
||||
static UARTDeviceState s_accessory_uart_state;
|
||||
static UARTDevice ACCESSORY_UART_DEVICE = {
|
||||
.state = &s_accessory_uart_state,
|
||||
.half_duplex = true,
|
||||
.tx_gpio = {
|
||||
.gpio = GPIOA,
|
||||
.gpio_pin = GPIO_Pin_11,
|
||||
.gpio_pin_source = GPIO_PinSource11,
|
||||
.gpio_af = GPIO_AF_USART6
|
||||
},
|
||||
.periph = USART6,
|
||||
.irq_channel = USART6_IRQn,
|
||||
.irq_priority = 0xb,
|
||||
.rcc_apb_periph = RCC_APB2Periph_USART6,
|
||||
.rx_dma = &ACCESSORY_UART_RX_DMA_REQUEST
|
||||
};
|
||||
UARTDevice * const ACCESSORY_UART = &ACCESSORY_UART_DEVICE;
|
||||
IRQ_MAP(USART6, uart_irq_handler, ACCESSORY_UART);
|
||||
|
||||
|
||||
// I2C DEVICES
|
||||
|
||||
static I2CBusState I2C_PMIC_HRM_BUS_STATE = {};
|
||||
|
||||
static const I2CBusHal I2C_PMIC_HRM_BUS_HAL = {
|
||||
.i2c = I2C3,
|
||||
.clock_ctrl = RCC_APB1Periph_I2C3,
|
||||
.clock_speed = 400000,
|
||||
.duty_cycle = I2CDutyCycle_2,
|
||||
.ev_irq_channel = I2C3_EV_IRQn,
|
||||
.er_irq_channel = I2C3_ER_IRQn,
|
||||
};
|
||||
|
||||
static const I2CBus I2C_PMIC_HRM_BUS = {
|
||||
.state = &I2C_PMIC_HRM_BUS_STATE,
|
||||
.hal = &I2C_PMIC_HRM_BUS_HAL,
|
||||
.scl_gpio = {
|
||||
.gpio = GPIOA,
|
||||
.gpio_pin = GPIO_Pin_8,
|
||||
.gpio_pin_source = GPIO_PinSource8,
|
||||
.gpio_af = GPIO_AF_I2C3
|
||||
},
|
||||
.sda_gpio = {
|
||||
.gpio = GPIOB,
|
||||
.gpio_pin = GPIO_Pin_8,
|
||||
.gpio_pin_source = GPIO_PinSource8,
|
||||
.gpio_af = GPIO_AF9_I2C3
|
||||
},
|
||||
.stop_mode_inhibitor = InhibitorI2C3,
|
||||
.name = "I2C_PMIC"
|
||||
};
|
||||
|
||||
static const I2CSlavePort I2C_SLAVE_AS3701B = {
|
||||
.bus = &I2C_PMIC_HRM_BUS,
|
||||
.address = 0x80
|
||||
};
|
||||
|
||||
I2CSlavePort * const I2C_AS3701B = &I2C_SLAVE_AS3701B;
|
||||
|
||||
IRQ_MAP(I2C3_EV, i2c_hal_event_irq_handler, &I2C_PMIC_HRM_BUS);
|
||||
IRQ_MAP(I2C3_ER, i2c_hal_error_irq_handler, &I2C_PMIC_HRM_BUS);
|
||||
|
||||
|
||||
// VOLTAGE MONITOR DEVICES
|
||||
static const VoltageMonitorDevice VOLTAGE_MONITOR_ALS_DEVICE = {
|
||||
.adc = ADC1,
|
||||
.adc_channel = ADC_Channel_13,
|
||||
.clock_ctrl = RCC_APB2Periph_ADC1,
|
||||
.input = {
|
||||
.gpio = GPIOC,
|
||||
.gpio_pin = GPIO_Pin_3,
|
||||
},
|
||||
};
|
||||
|
||||
static const VoltageMonitorDevice VOLTAGE_MONITOR_BATTERY_DEVICE = {
|
||||
.adc = ADC1,
|
||||
.adc_channel = ADC_Channel_5,
|
||||
.clock_ctrl = RCC_APB2Periph_ADC1,
|
||||
.input = {
|
||||
.gpio = GPIOA,
|
||||
.gpio_pin = GPIO_Pin_5,
|
||||
},
|
||||
};
|
||||
|
||||
static const VoltageMonitorDevice VOLTAGE_MONITOR_TEMPERATURE_DEVICE = {
|
||||
.adc = ADC1,
|
||||
.adc_channel = ADC_Channel_TempSensor,
|
||||
.clock_ctrl = RCC_APB2Periph_ADC1,
|
||||
// .input not applicable
|
||||
};
|
||||
|
||||
const VoltageMonitorDevice * VOLTAGE_MONITOR_ALS = &VOLTAGE_MONITOR_ALS_DEVICE;
|
||||
const VoltageMonitorDevice * VOLTAGE_MONITOR_BATTERY = &VOLTAGE_MONITOR_BATTERY_DEVICE;
|
||||
const VoltageMonitorDevice * VOLTAGE_MONITOR_TEMPERATURE = &VOLTAGE_MONITOR_TEMPERATURE_DEVICE;
|
||||
|
||||
// Temperature sensor
|
||||
// STM32F412 datasheet rev 2
|
||||
// Section 6.3.21
|
||||
TemperatureSensor const TEMPERATURE_SENSOR_DEVICE = {
|
||||
.voltage_monitor = &VOLTAGE_MONITOR_TEMPERATURE_DEVICE,
|
||||
.millivolts_ref = 760,
|
||||
.millidegrees_ref = 25000,
|
||||
.slope_numerator = 5,
|
||||
.slope_denominator = 2000,
|
||||
};
|
||||
|
||||
TemperatureSensor * const TEMPERATURE_SENSOR = &TEMPERATURE_SENSOR_DEVICE;
|
||||
|
||||
|
||||
//
|
||||
// SPI Bus configuration
|
||||
//
|
||||
|
||||
static SPIBusState DIALOG_SPI_BUS_STATE = { };
|
||||
static const SPIBus DIALOG_SPI_BUS = {
|
||||
.state = &DIALOG_SPI_BUS_STATE,
|
||||
.spi = SPI5,
|
||||
.spi_sclk = { GPIOB, GPIO_Pin_0, GPIO_PinSource0, GPIO_AF6_SPI5 },
|
||||
.spi_miso = { GPIOA, GPIO_Pin_12, GPIO_PinSource12, GPIO_AF6_SPI5 },
|
||||
.spi_mosi = { GPIOA, GPIO_Pin_10, GPIO_PinSource10, GPIO_AF6_SPI5 },
|
||||
.spi_sclk_speed = GPIO_Speed_50MHz,
|
||||
// DA14680_FS v1.4 page 89:
|
||||
// "In slave mode the internal SPI clock must be more than four times the SPIx_CLK"
|
||||
// The system clock is 16MHz, so don't use more than 4MHz.
|
||||
.spi_clock_speed_hz = MHZ_TO_HZ(4)
|
||||
};
|
||||
|
||||
//
|
||||
// SPI Slave port configuration
|
||||
//
|
||||
|
||||
static SPISlavePortState DIALOG_SPI_SLAVE_PORT_STATE = {};
|
||||
static SPISlavePort DIALOG_SPI_SLAVE_PORT = {
|
||||
.slave_state = &DIALOG_SPI_SLAVE_PORT_STATE,
|
||||
.spi_bus = &DIALOG_SPI_BUS,
|
||||
.spi_scs = { GPIOB, GPIO_Pin_1, false },
|
||||
.spi_direction = SpiDirection_2LinesFullDuplex,
|
||||
.spi_cpol = SpiCPol_Low,
|
||||
.spi_cpha = SpiCPha_1Edge,
|
||||
.spi_first_bit = SpiFirstBit_MSB,
|
||||
.rx_dma = &DIALOG_SPI_RX_DMA_REQUEST,
|
||||
.tx_dma = &DIALOG_SPI_TX_DMA_REQUEST
|
||||
};
|
||||
SPISlavePort * const DIALOG_SPI = &DIALOG_SPI_SLAVE_PORT;
|
||||
|
||||
|
||||
// QSPI
|
||||
static QSPIPortState s_qspi_port_state;
|
||||
static QSPIPort QSPI_PORT = {
|
||||
.state = &s_qspi_port_state,
|
||||
.clock_speed_hz = MHZ_TO_HZ(50),
|
||||
.auto_polling_interval = 16,
|
||||
.clock_ctrl = RCC_AHB3Periph_QSPI,
|
||||
.cs_gpio = {
|
||||
.gpio = GPIOB,
|
||||
.gpio_pin = GPIO_Pin_6,
|
||||
.gpio_pin_source = GPIO_PinSource6,
|
||||
.gpio_af = GPIO_AF10_QUADSPI,
|
||||
},
|
||||
.clk_gpio = {
|
||||
.gpio = GPIOB,
|
||||
.gpio_pin = GPIO_Pin_2,
|
||||
.gpio_pin_source = GPIO_PinSource2,
|
||||
.gpio_af = GPIO_AF9_QUADSPI,
|
||||
},
|
||||
.data_gpio = {
|
||||
{
|
||||
.gpio = GPIOC,
|
||||
.gpio_pin = GPIO_Pin_9,
|
||||
.gpio_pin_source = GPIO_PinSource9,
|
||||
.gpio_af = GPIO_AF9_QUADSPI,
|
||||
},
|
||||
{
|
||||
.gpio = GPIOC,
|
||||
.gpio_pin = GPIO_Pin_10,
|
||||
.gpio_pin_source = GPIO_PinSource10,
|
||||
.gpio_af = GPIO_AF9_QUADSPI,
|
||||
},
|
||||
{
|
||||
.gpio = GPIOC,
|
||||
.gpio_pin = GPIO_Pin_8,
|
||||
.gpio_pin_source = GPIO_PinSource8,
|
||||
.gpio_af = GPIO_AF9_QUADSPI,
|
||||
},
|
||||
{
|
||||
.gpio = GPIOA,
|
||||
.gpio_pin = GPIO_Pin_1,
|
||||
.gpio_pin_source = GPIO_PinSource1,
|
||||
.gpio_af = GPIO_AF9_QUADSPI,
|
||||
},
|
||||
},
|
||||
.dma = &QSPI_DMA_REQUEST,
|
||||
};
|
||||
QSPIPort * const QSPI = &QSPI_PORT;
|
||||
|
||||
static QSPIFlashState s_qspi_flash_state;
|
||||
static QSPIFlash QSPI_FLASH_DEVICE = {
|
||||
.state = &s_qspi_flash_state,
|
||||
.qspi = &QSPI_PORT,
|
||||
.default_fast_read_ddr_enabled = false,
|
||||
.reset_gpio = { GPIO_Port_NULL },
|
||||
};
|
||||
QSPIFlash * const QSPI_FLASH = &QSPI_FLASH_DEVICE;
|
||||
|
||||
|
||||
void board_early_init(void) {
|
||||
}
|
||||
|
||||
void board_init(void) {
|
||||
i2c_init(&I2C_PMIC_HRM_BUS);
|
||||
|
||||
voltage_monitor_device_init(VOLTAGE_MONITOR_ALS);
|
||||
voltage_monitor_device_init(VOLTAGE_MONITOR_BATTERY);
|
||||
|
||||
qspi_init(QSPI, BOARD_NOR_FLASH_SIZE);
|
||||
}
|
||||
Reference in New Issue
Block a user