Files
RadioPhotonic_PCB_software/App/Devices/board_io.c
2026-04-24 16:51:15 +03:00

258 lines
8.3 KiB
C

/**
* @file board_io.c
* @brief Board-specific GPIO and shared low-level control helpers.
*/
#include "board_io.h"
#define UI_LCD_CONTRAST_PWM_FREQUENCY_HZ 20000u
#define UI_LCD_CONTRAST_PWM_PERIOD_COUNTS 1000u
#define UI_LCD_CONTRAST_PWM_DUTY_PERMILLE 300u
static TIM_HandleTypeDef g_ui_lcd_contrast_pwm_timer;
static uint32_t board_io_get_apb1_timer_clock_hz(void);
static void board_io_init_lcd_contrast_pwm(void);
void board_io_enable_uart_rx_irq(void)
{
LL_USART_EnableIT_PE(USART1);
LL_USART_EnableIT_RXNE(USART1);
LL_USART_EnableIT_ERROR(USART1);
NVIC_SetPriority(USART1_IRQn, 0);
NVIC_EnableIRQ(USART1_IRQn);
}
void board_io_init_standalone_ui(void)
{
GPIO_InitTypeDef gpio_init = {0};
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
HAL_GPIO_WritePin(UI_LCD_RS_GPIO_Port,
UI_LCD_RS_Pin | UI_LCD_E_Pin | UI_LCD_D4_Pin | UI_LCD_D5_Pin | UI_LCD_D6_Pin | UI_LCD_D7_Pin,
GPIO_PIN_RESET);
/*
* A fixed contrast pin is only a compromise until a potentiometer is
* added. Driving V0 low is the safest default for HD44780/SPLC780D-style
* modules because it makes characters visible instead of appearing blank.
*/
HAL_GPIO_WritePin(UI_LCD_V0_REF_GPIO_Port, UI_LCD_V0_REF_Pin, GPIO_PIN_RESET);
gpio_init.Pin = UI_LCD_RS_Pin | UI_LCD_E_Pin | UI_LCD_D4_Pin | UI_LCD_D5_Pin | UI_LCD_D6_Pin | UI_LCD_D7_Pin;
gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init.Pull = GPIO_NOPULL;
gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOG, &gpio_init);
gpio_init.Pin = UI_LCD_V0_REF_Pin;
gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init.Pull = GPIO_NOPULL;
gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(UI_LCD_V0_REF_GPIO_Port, &gpio_init);
gpio_init.Pin = UI_BUTTON_Pin;
gpio_init.Mode = GPIO_MODE_INPUT;
gpio_init.Pull = GPIO_PULLUP;
HAL_GPIO_Init(UI_BUTTON_GPIO_Port, &gpio_init);
board_io_init_lcd_contrast_pwm();
}
static uint32_t board_io_get_apb1_timer_clock_hz(void)
{
uint32_t pclk1_hz = HAL_RCC_GetPCLK1Freq();
if ((RCC->CFGR & RCC_CFGR_PPRE1) == RCC_CFGR_PPRE1_DIV1)
{
return pclk1_hz;
}
return pclk1_hz * 2u;
}
static void board_io_init_lcd_contrast_pwm(void)
{
GPIO_InitTypeDef gpio_init = {0};
TIM_OC_InitTypeDef pwm_channel = {0};
uint32_t timer_clock_hz = board_io_get_apb1_timer_clock_hz();
uint32_t prescaler_divisor = timer_clock_hz / (UI_LCD_CONTRAST_PWM_FREQUENCY_HZ * UI_LCD_CONTRAST_PWM_PERIOD_COUNTS);
uint32_t pulse_counts = ((UI_LCD_CONTRAST_PWM_PERIOD_COUNTS * UI_LCD_CONTRAST_PWM_DUTY_PERMILLE) + 999u) / 1000u;
if (prescaler_divisor == 0u)
{
prescaler_divisor = 1u;
}
if (pulse_counts >= UI_LCD_CONTRAST_PWM_PERIOD_COUNTS)
{
pulse_counts = UI_LCD_CONTRAST_PWM_PERIOD_COUNTS - 1u;
}
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_TIM4_CLK_ENABLE();
/*
* This PWM output is intended for the LCD contrast input (V0) through a
* simple RC low-pass filter. Keeping it local to board_io.c avoids
* spreading board wiring assumptions into higher-level UI code.
*/
gpio_init.Pin = UI_LCD_CONTRAST_PWM_Pin;
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Pull = GPIO_NOPULL;
gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
gpio_init.Alternate = GPIO_AF2_TIM4;
HAL_GPIO_Init(UI_LCD_CONTRAST_PWM_GPIO_Port, &gpio_init);
g_ui_lcd_contrast_pwm_timer.Instance = TIM4;
g_ui_lcd_contrast_pwm_timer.Init.Prescaler = (uint32_t)(prescaler_divisor - 1u);
g_ui_lcd_contrast_pwm_timer.Init.CounterMode = TIM_COUNTERMODE_UP;
g_ui_lcd_contrast_pwm_timer.Init.Period = UI_LCD_CONTRAST_PWM_PERIOD_COUNTS - 1u;
g_ui_lcd_contrast_pwm_timer.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
g_ui_lcd_contrast_pwm_timer.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&g_ui_lcd_contrast_pwm_timer) != HAL_OK)
{
return;
}
pwm_channel.OCMode = TIM_OCMODE_PWM1;
pwm_channel.Pulse = pulse_counts;
pwm_channel.OCPolarity = TIM_OCPOLARITY_HIGH;
pwm_channel.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&g_ui_lcd_contrast_pwm_timer, &pwm_channel, TIM_CHANNEL_3) != HAL_OK)
{
return;
}
(void)HAL_TIM_PWM_Start(&g_ui_lcd_contrast_pwm_timer, TIM_CHANNEL_3);
}
void board_io_reset_runtime_outputs(void)
{
HAL_GPIO_WritePin(EN_5V1_GPIO_Port, EN_5V1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(EN_5V2_GPIO_Port, EN_5V2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LD1_EN_GPIO_Port, LD1_EN_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LD2_EN_GPIO_Port, LD2_EN_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(REF0_EN_GPIO_Port, REF0_EN_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(REF2_ON_GPIO_Port, REF2_ON_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(TECEN1_GPIO_Port, TECEN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(TECEN2_GPIO_Port, TECEN2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(TEC1_PD_GPIO_Port, TEC1_PD_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(TEC2_PD_GPIO_Port, TEC2_PD_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(ADC_MPD1_CS_GPIO_Port, ADC_MPD1_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(ADC_MPD2_CS_GPIO_Port, ADC_MPD2_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SPI4_CNV_GPIO_Port, SPI4_CNV_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SPI5_CNV_GPIO_Port, SPI5_CNV_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(DAC_LD1_CS_GPIO_Port, DAC_LD1_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(DAC_LD2_CS_GPIO_Port, DAC_LD2_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(DAC_TEC1_CS_GPIO_Port, DAC_TEC1_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(DAC_TEC2_CS_GPIO_Port, DAC_TEC2_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(AD9102_CS_GPIO_Port, AD9102_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(AD9833_CS_GPIO_Port, AD9833_CS_Pin, GPIO_PIN_SET);
}
void board_io_configure_spi2_mode(uint32_t polarity, uint32_t phase)
{
if (LL_SPI_IsEnabled(SPI2))
{
LL_SPI_Disable(SPI2);
}
LL_SPI_SetClockPolarity(SPI2, polarity);
LL_SPI_SetClockPhase(SPI2, phase);
if (!LL_SPI_IsEnabled(SPI2))
{
LL_SPI_Enable(SPI2);
}
}
bool board_io_is_usb_connected(void)
{
return HAL_GPIO_ReadPin(USB_FLAG_GPIO_Port, USB_FLAG_Pin) == GPIO_PIN_SET;
}
bool board_io_is_sd_card_present(void)
{
return HAL_GPIO_ReadPin(SDMMC1_EN_GPIO_Port, SDMMC1_EN_Pin) == GPIO_PIN_RESET;
}
bool board_io_is_standalone_ui_button_pressed(void)
{
return HAL_GPIO_ReadPin(UI_BUTTON_GPIO_Port, UI_BUTTON_Pin) == GPIO_PIN_RESET;
}
void board_io_set_supply_enabled(uint8_t supply_index, bool enabled)
{
GPIO_PinState pin_state = enabled ? GPIO_PIN_SET : GPIO_PIN_RESET;
if (supply_index == 1u)
{
HAL_GPIO_WritePin(EN_5V1_GPIO_Port, EN_5V1_Pin, pin_state);
}
else if (supply_index == 2u)
{
HAL_GPIO_WritePin(EN_5V2_GPIO_Port, EN_5V2_Pin, pin_state);
}
}
void board_io_set_laser_enabled(uint8_t laser_index, bool enabled)
{
GPIO_PinState pin_state = enabled ? GPIO_PIN_SET : GPIO_PIN_RESET;
if (laser_index == 1u)
{
HAL_GPIO_WritePin(LD1_EN_GPIO_Port, LD1_EN_Pin, pin_state);
}
else if (laser_index == 2u)
{
HAL_GPIO_WritePin(LD2_EN_GPIO_Port, LD2_EN_Pin, pin_state);
}
}
void board_io_set_reference_enabled(uint8_t reference_index, bool enabled)
{
GPIO_PinState pin_state = enabled ? GPIO_PIN_SET : GPIO_PIN_RESET;
if (reference_index == 1u)
{
HAL_GPIO_WritePin(REF0_EN_GPIO_Port, REF0_EN_Pin, pin_state);
}
else if (reference_index == 2u)
{
HAL_GPIO_WritePin(REF2_ON_GPIO_Port, REF2_ON_Pin, pin_state);
}
}
void board_io_set_tec_channel_enabled(uint8_t tec_index, bool enabled)
{
GPIO_PinState pin_state = enabled ? GPIO_PIN_SET : GPIO_PIN_RESET;
if (tec_index == 1u)
{
HAL_GPIO_WritePin(TEC1_PD_GPIO_Port, TEC1_PD_Pin, pin_state);
HAL_GPIO_WritePin(TECEN1_GPIO_Port, TECEN1_Pin, pin_state);
}
else if (tec_index == 2u)
{
HAL_GPIO_WritePin(TEC2_PD_GPIO_Port, TEC2_PD_Pin, pin_state);
HAL_GPIO_WritePin(TECEN2_GPIO_Port, TECEN2_Pin, pin_state);
}
}
void board_io_write_signal(GPIO_TypeDef *port, uint16_t pin, bool level_high)
{
HAL_GPIO_WritePin(port, pin, level_high ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
void board_io_toggle_debug_pin(void)
{
HAL_GPIO_TogglePin(TEST_01_GPIO_Port, TEST_01_Pin);
}