#include "general.h"
#include "platform.h"
#include "usb.h"
#include "aux_serial.h"
#include "morse.h"
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/scs.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/adc.h>
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/flash.h>
#include <libopencm3/stm32/timer.h>
static void adc_init(void);
static void setup_vbus_irq(void);
extern char vector_table;
#define TPWR_SOFT_START_STEPS 64U
#define BMP_HWVERSION_BYTE FLASH_OPTION_BYTE_2
int platform_hwversion(void)
{
static int hwversion = -1;
uint16_t hwversion_pins = GPIO7 | GPIO6 | GPIO5;
uint16_t unused_pins = hwversion_pins ^ 0xffffU;
if (hwversion == -1) {
if (BMP_HWVERSION_BYTE != 0xffffU && BMP_HWVERSION_BYTE != 0x00ffU) {
if ((BMP_HWVERSION_BYTE >> 8U) != (~BMP_HWVERSION_BYTE & 0xffU) || (BMP_HWVERSION_BYTE & 0xffU) < 4)
return -2;
hwversion = BMP_HWVERSION_BYTE & 0xffU;
}
}
if (hwversion == -1) {
gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, hwversion_pins);
gpio_set(GPIOB, hwversion_pins);
for (volatile size_t i = 0; i < 100U; ++i)
continue;
uint16_t pins_negative = gpio_get(GPIOB, hwversion_pins) | unused_pins;
gpio_clear(GPIOB, hwversion_pins);
for (volatile size_t i = 0; i < 100U; ++i)
continue;
uint16_t pins_positive = gpio_get(GPIOB, hwversion_pins);
hwversion = (((pins_positive ^ pins_negative) ^ 0xffffU) & hwversion_pins) >> 5U;
}
return hwversion;
}
void platform_init(void)
{
const int hwversion = platform_hwversion();
SCS_DEMCR |= SCS_DEMCR_VC_MON_EN;
rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
rcc_periph_clock_enable(RCC_USB);
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
if (hwversion >= 6)
rcc_periph_clock_enable(RCC_GPIOC);
if (hwversion >= 1)
rcc_periph_clock_enable(RCC_TIM1);
rcc_periph_clock_enable(RCC_AFIO);
rcc_periph_clock_enable(RCC_CRC);
gpio_clear(USB_PU_PORT, USB_PU_PIN);
gpio_set_mode(USB_PU_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, USB_PU_PIN);
gpio_set_mode(JTAG_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, TMS_DIR_PIN | TCK_PIN | TDI_PIN);
gpio_set_mode(JTAG_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_INPUT_FLOAT, TMS_PIN);
gpio_port_write(GPIOA, 0x8102);
gpio_port_write(GPIOB, 0x2000);
gpio_port_write(GPIOA, 0x8182);
gpio_port_write(GPIOB, 0x2002);
if (hwversion >= 6) {
gpio_set_mode(TCK_DIR_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, TCK_DIR_PIN);
gpio_set_mode(TCK_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, TCK_PIN);
gpio_clear(TCK_DIR_PORT, TCK_DIR_PIN);
}
gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_UART | LED_IDLE_RUN | LED_ERROR);
platform_nrst_set_val(false);
gpio_set_mode(NRST_PORT, GPIO_MODE_OUTPUT_50_MHZ,
hwversion == 0 || hwversion >= 3 ? GPIO_CNF_OUTPUT_PUSHPULL : GPIO_CNF_OUTPUT_OPENDRAIN, NRST_PIN);
if (hwversion < 3)
gpio_set_mode(NRST_SENSE_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, NRST_SENSE_PIN);
else {
gpio_set(NRST_SENSE_PORT, NRST_SENSE_PIN);
gpio_set_mode(NRST_SENSE_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, NRST_SENSE_PIN);
}
if (hwversion == 1) {
gpio_set(PWR_BR_PORT, PWR_BR_PIN);
gpio_set_mode(PWR_BR_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, PWR_BR_PIN);
} else if (hwversion > 1) {
gpio_set(PWR_BR_PORT, PWR_BR_PIN);
gpio_set_mode(PWR_BR_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, PWR_BR_PIN);
}
if (hwversion >= 1) {
gpio_primary_remap(AFIO_MAPR_SWJ_CFG_FULL_SWJ, AFIO_MAPR_TIM1_REMAP_PARTIAL_REMAP);
timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
timer_set_oc_polarity_low(TIM1, TIM_OC3N);
timer_enable_oc_output(TIM1, TIM_OC3N);
timer_set_oc_value(TIM1, TIM_OC3, 0);
timer_set_deadtime(TIM1, 0);
timer_set_period(TIM1, TPWR_SOFT_START_STEPS - 1U);
timer_enable_break_main_output(TIM1);
timer_continuous_mode(TIM1);
timer_update_on_overflow(TIM1);
timer_enable_counter(TIM1);
}
if (hwversion >= 5) {
gpio_set_mode(AUX_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, AUX_SCLK | AUX_COPI);
gpio_set_mode(AUX_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, AUX_FCS | AUX_SDCS);
gpio_set_mode(AUX_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, AUX_CIPO);
gpio_set(AUX_PORT, AUX_FCS | AUX_SDCS);
if (hwversion >= 6) {
gpio_set_mode(AUX_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, AUX_DCS6);
gpio_set(AUX_PORT, AUX_DCS6);
}
}
if (hwversion > 0)
adc_init();
else {
gpio_clear(GPIOB, GPIO0);
gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO0);
}
SCB_VTOR = (uint32_t)&vector_table;
platform_timing_init();
blackmagic_usb_init();
if (hwversion == 0 || hwversion >= 3 || !(SCS_DEMCR & SCS_DEMCR_TRCENA))
aux_serial_init();
setup_vbus_irq();
}
void platform_nrst_set_val(bool assert)
{
gpio_set(TMS_PORT, TMS_PIN);
if (platform_hwversion() == 0 || platform_hwversion() >= 3)
gpio_set_val(NRST_PORT, NRST_PIN, assert);
else
gpio_set_val(NRST_PORT, NRST_PIN, !assert);
if (assert) {
for (volatile size_t i = 0; i < 10000U; ++i)
continue;
}
}
bool platform_nrst_get_val(void)
{
if (platform_hwversion() == 0)
return gpio_get(NRST_SENSE_PORT, NRST_SENSE_PIN) == 0;
if (platform_hwversion() >= 3)
return gpio_get(NRST_SENSE_PORT, NRST_SENSE_PIN) != 0;
return gpio_get(NRST_PORT, NRST_PIN) == 0;
}
bool platform_target_get_power(void)
{
if (platform_hwversion() > 0)
return !gpio_get(PWR_BR_PORT, PWR_BR_PIN);
return false;
}
static inline void platform_wait_pwm_cycle()
{
while (!timer_get_flag(TIM1, TIM_SR_UIF))
continue;
timer_clear_flag(TIM1, TIM_SR_UIF);
}
bool platform_target_set_power(const bool power)
{
if (platform_hwversion() <= 0)
return false;
if (power) {
gpio_set_mode(PWR_BR_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, PWR_BR_PIN);
timer_clear_flag(TIM1, TIM_SR_UIF);
platform_wait_pwm_cycle();
for (size_t step = 1U; step < TPWR_SOFT_START_STEPS; ++step) {
timer_set_oc_value(TIM1, TIM_OC3, step);
platform_wait_pwm_cycle();
}
}
gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power);
if (power) {
if (platform_hwversion() == 1)
gpio_set_mode(PWR_BR_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, PWR_BR_PIN);
else
gpio_set_mode(PWR_BR_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, PWR_BR_PIN);
timer_set_oc_value(TIM1, TIM_OC3, 0U);
}
return true;
}
static void adc_init(void)
{
rcc_periph_clock_enable(RCC_ADC1);
gpio_set_mode(TPWR_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, TPWR_PIN);
adc_power_off(ADC1);
adc_disable_scan_mode(ADC1);
adc_set_single_conversion_mode(ADC1);
adc_disable_external_trigger_regular(ADC1);
adc_set_right_aligned(ADC1);
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_239DOT5CYC);
adc_enable_temperature_sensor();
adc_power_on(ADC1);
for (volatile size_t i = 0; i < 800000U; ++i)
continue;
adc_reset_calibration(ADC1);
adc_calibrate(ADC1);
}
uint32_t platform_target_voltage_sense(void)
{
if (platform_hwversion() == 0)
return 0;
uint8_t channel = 8;
adc_set_regular_sequence(ADC1, 1, &channel);
adc_start_conversion_direct(ADC1);
while (!adc_eoc(ADC1))
continue;
uint32_t val = adc_read_regular(ADC1);
ADC_SR(ADC1) &= ~ADC_SR_EOC;
return (val * 99U) / 8191U;
}
const char *platform_target_voltage(void)
{
if (platform_hwversion() == 0)
return gpio_get(GPIOB, GPIO0) ? "OK" : "ABSENT!";
static char ret[] = "0.0V";
uint32_t val = platform_target_voltage_sense();
ret[0] = '0' + val / 10U;
ret[2] = '0' + val % 10U;
return ret;
}
void platform_request_boot(void)
{
gpio_set_mode(USB_PU_PORT, GPIO_MODE_INPUT, 0, USB_PU_PIN);
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
gpio_clear(GPIOB, GPIO12);
}
void platform_target_clk_output_enable(bool enable)
{
if (platform_hwversion() >= 6) {
if (!enable)
gpio_set_mode(TCK_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, TCK_PIN);
gpio_set_val(TCK_DIR_PORT, TCK_DIR_PIN, enable);
if (enable)
gpio_set_mode(TCK_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, TCK_PIN);
}
}
bool platform_spi_init(const spi_bus_e bus)
{
if (bus == SPI_BUS_EXTERNAL) {
rcc_periph_clock_enable(RCC_SPI1);
rcc_periph_reset_pulse(RST_SPI1);
platform_target_clk_output_enable(true);
gpio_set_mode(TCK_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, TCK_PIN);
gpio_set_mode(TDI_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, TDI_PIN);
gpio_set(TMS_DIR_PORT, TMS_DIR_PIN);
} else {
rcc_periph_clock_enable(RCC_SPI2);
rcc_periph_reset_pulse(RST_SPI2);
}
const uint32_t controller = bus == SPI_BUS_EXTERNAL ? EXT_SPI : AUX_SPI;
spi_init_master(controller, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST);
spi_enable(controller);
return true;
}
bool platform_spi_deinit(spi_bus_e bus)
{
spi_disable(bus == SPI_BUS_EXTERNAL ? EXT_SPI : AUX_SPI);
if (bus == SPI_BUS_EXTERNAL) {
rcc_periph_clock_disable(RCC_SPI1);
gpio_set_mode(TCK_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, TCK_PIN);
gpio_set_mode(TDI_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, TDI_PIN);
platform_target_clk_output_enable(false);
} else
rcc_periph_clock_disable(RCC_SPI2);
return true;
}
bool platform_spi_chip_select(const uint8_t device_select)
{
const uint8_t device = device_select & 0x7fU;
const bool select = !(device_select & 0x80U);
uint32_t port = AUX_PORT;
uint16_t pin;
switch (device) {
case SPI_DEVICE_INT_FLASH:
pin = AUX_FCS;
break;
case SPI_DEVICE_EXT_FLASH:
port = EXT_SPI_CS_PORT;
pin = EXT_SPI_CS;
break;
case SPI_DEVICE_SDCARD:
pin = AUX_SDCS;
break;
case SPI_DEVICE_DISPLAY:
pin = AUX_DCS;
break;
default:
return false;
}
gpio_set_val(port, pin, select);
return true;
}
uint8_t platform_spi_xfer(const spi_bus_e bus, const uint8_t value)
{
return spi_xfer(bus == SPI_BUS_EXTERNAL ? EXT_SPI : AUX_SPI, value);
}
void exti15_10_isr(void)
{
uint32_t usb_vbus_port;
uint16_t usb_vbus_pin;
if (platform_hwversion() < 5) {
usb_vbus_port = USB_VBUS_PORT;
usb_vbus_pin = USB_VBUS_PIN;
} else {
usb_vbus_port = USB_VBUS5_PORT;
usb_vbus_pin = USB_VBUS5_PIN;
}
if (gpio_get(usb_vbus_port, usb_vbus_pin))
gpio_set_mode(USB_PU_PORT, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, USB_PU_PIN);
else
gpio_set_mode(USB_PU_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, USB_PU_PIN);
exti_reset_request(usb_vbus_pin);
}
static void setup_vbus_irq(void)
{
uint32_t usb_vbus_port;
uint16_t usb_vbus_pin;
if (platform_hwversion() < 5) {
usb_vbus_port = USB_VBUS_PORT;
usb_vbus_pin = USB_VBUS_PIN;
} else {
usb_vbus_port = USB_VBUS5_PORT;
usb_vbus_pin = USB_VBUS5_PIN;
}
nvic_set_priority(USB_VBUS_IRQ, IRQ_PRI_USB_VBUS);
nvic_enable_irq(USB_VBUS_IRQ);
gpio_set(usb_vbus_port, usb_vbus_pin);
gpio_set(USB_PU_PORT, USB_PU_PIN);
gpio_set_mode(usb_vbus_port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, usb_vbus_pin);
exti_select_source(usb_vbus_pin, usb_vbus_port);
exti_set_trigger(usb_vbus_pin, EXTI_TRIGGER_BOTH);
exti_enable_request(usb_vbus_pin);
exti15_10_isr();
}