Loading files
dd69bd05aThis file is pinned to the selected release. Download the original to open it in your design tool.
// * This file is part of the Tinymovr-Firmware distribution
// * (https://github.com/yconst/tinymovr-firmware).
// * Copyright (c) 2020-2023 Ioannis Chatzikonstantinou.
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, version 3.
// *
// * This program is distributed in the hope that it will be useful, but
// * WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// * General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <src/adc/adc.h>
#include <src/utils/utils.h>
#include <src/rtt/SEGGER_RTT.h>
#include <src/controller/controller.h>
#include <src/motor/motor.h>
#include <src/can/can_endpoints.h>
#include <src/sensor/sensor.h>
#include <src/observer/observer.h>
#include <src/system/system.h>
__attribute__((section(".shared"))) volatile uint32_t shared_data;
static SystemState state = {0};
static SystemConfig config = {
.Vbus_tau = 0.001f
};
void system_init(void)
{
// --- Mandatory System Init from Qorvo
// Set Flash Lock to allow write access to MEMCTL register for configuring clocks
PAC55XX_MEMCTL->FLASHLOCK = FLASH_LOCK_ALLOW_WRITE_MEMCTL;
// Turn on Flash Cache
PAC55XX_MEMCTL->MEMCTL.CACHEDIS = 0;
// Always make sure MCLK is set to use ROSC CLK when making changes to FRCLK, SCLK, or HCLK
PAC55XX_MEMCTL->MEMCTL.MCLKSEL = MEMCTL_MCLK_ROSCCLK; // MCLK = ROSCCLK
// Select SCLK = FRCLK before making changes to FRCLK or PLLCLK
PAC55XX_SCC->CCSCTL.SCLKMUXSEL = CCSCTL_SCLK_FRCLK;
// Select 4 MHz CLKREF for Free Running Clock FRCLK
PAC55XX_SCC->CCSCTL.FRCLKMUXSEL = CCSCTL_CLKIN_CLKREF;
pac5xxx_sys_pll_config_enable(4, 300, 0); // PLLCLK = 300 MHz = (4/4 * 300) /1
// Configure SCLK=PLLCLK=300 MHz, HCLK=150 MHz, PCLK=150 MHz, ACLK=300 MHz and WaitStates; Use default PCLKDIV=1
PAC55XX_SCC->CCSCTL.HCLKDIV = CCSCTL_HCLKDIV_DIV2; // HCLK = 150 MHz = SCLK/2; when SCLK = PLLCLK
PAC55XX_SCC->CCSCTL.ACLKDIV = CCSCTL_ACLKDIV_DIV1;
PAC55XX_MEMCTL->MEMCTL.WSTATE = 5 + 1; // Flash = 150/25 = 6 clocks = 5 WS; So, need 5 + 1 Extra WS
PAC55XX_SCC->CCSCTL.SCLKMUXSEL = CCSCTL_SCLK_PLLCLK; // SCLK = PLLCLK
// Set MCLK for Flash write & erase in addition to read
PAC55XX_MEMCTL->MEMCTL.MCLKDIV = MEMCTL_MCLK_DIV5; // MCLK will = HCLK/5 when MCLKSEL = MEMCTL_MCLK_HCLKDIV
PAC55XX_MEMCTL->MEMCTL.MCLKSEL = MEMCTL_MCLK_HCLKDIV; // MCLK = HCLK/5 = 30 MHz; allows reading and writing of Flash
PAC55XX_MEMCTL->FLASHLOCK = 0; // Disallow write access to MEMCTL
// Enable GPIO Input clock synchronization; should always be enabled, especially when using GPIO edge based interrupts
PAC55XX_GPIOA->CLKSYNC.w = 0xFF;
PAC55XX_GPIOB->CLKSYNC.w = 0xFF;
PAC55XX_GPIOC->CLKSYNC.w = 0xFF;
PAC55XX_GPIOD->CLKSYNC.w = 0xFF;
PAC55XX_GPIOE->CLKSYNC.w = 0xFF;
PAC55XX_GPIOF->CLKSYNC.w = 0xFF;
PAC55XX_GPIOG->CLKSYNC.w = 0xFF;
// --- End Mandatory System Init from Qorvo
// Configure SOC Bridge for talking to CAFE
pac5xxx_tile_socbridge_config(1, 0);
// System Configuration Power Options
// Vp = 10V , 440mA-540mA, Charge Pump Enable
pac5xxx_tile_register_write(ADDR_SYSCONF, 0x01);
// Ensure shared data is 0xFF and ADC GP0 register
// is zero, to bypass DFU mode on next boot
shared_data = 0xFF;
pac5xxx_tile_register_write(ADDR_GP0, 0);
// Configure reporting of mcu cycles
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
// Configure error handling
SCB->CCR |= 0x10;
// Arbitrary value to avoid division by zero
state.Vbus = 12.0f;
// Derive VBus D value for given tau value
config.Vbus_D = 1.0f - powf(EPSILON, -1.0f / (config.Vbus_tau * SYSTICK_FREQ_HZ));
/* Initialize Systick per 1ms */
SysTick_Config(150000); // TODO: Use var
}
TM_RAMFUNC void system_update(void)
{
state.Vbus += config.Vbus_D * (((float)PAC55XX_ADC->DTSERES4.VAL) * VBUS_SCALING_FACTOR - state.Vbus);
if (state.Vbus < VBUS_LOW_THRESHOLD)
{
state.errors |= ERRORS_UNDERVOLTAGE;
}
}
void system_reset(void)
{
// shared RAM and GP0 register is already zeroed at `system_init()`
NVIC_SystemReset();
}
void system_enter_dfu(void)
{
shared_data = BTL_TRIGGER_PATTERN_RAM;
pac5xxx_tile_register_write(ADDR_GP0, BTL_TRIGGER_PATTERN);
NVIC_SystemReset();
}
void system_reset_calibration(void)
{
ADC_reset();
sensors_reset();
observers_init_with_defaults();
motor_reset_calibration();
wait_pwm_cycles(5000);
}
TM_RAMFUNC float system_get_Vbus(void)
{
return state.Vbus;
}
TM_RAMFUNC bool system_get_calibrated(void)
{
return (frames_get_calibrated() &&
motor_get_calibrated() &&
commutation_sensor_p->is_calibrated_func(commutation_sensor_p) &&
position_sensor_p->is_calibrated_func(position_sensor_p));
}
TM_RAMFUNC uint8_t system_get_errors(void)
{
return state.errors;
}
TM_RAMFUNC uint8_t system_get_warnings(void)
{
// As the user request rate is less than the update
// rate, and the warnings do not affect system integrity
// evaluation, it is better to fetch the registers per
// request
const uint8_t warnings = ((pac5xxx_tile_register_read(ADDR_STATDRV) & 0x56)) |
((pac5xxx_tile_register_read(ADDR_DRV_FLT) & 0x5));
return warnings;
}
TM_RAMFUNC bool errors_exist(void)
{
return (controller_get_errors() ||
commutation_sensor_p->get_errors_func(commutation_sensor_p) ||
position_sensor_p->get_errors_func(position_sensor_p) ||
motor_get_errors() ||
planner_get_errors() ||
system_get_errors());
}
void printUsageErrorMsg(uint32_t CFSRValue)
{
SEGGER_RTT_WriteString(0, "Usage fault: ");
CFSRValue >>= 16; // right shift to lsb
if ((CFSRValue & (1 << 9)) != 0)
{
SEGGER_RTT_WriteString(0, "Divide by zero\r\n");
}
}
void HardFault_Handler(void)
{
SEGGER_RTT_WriteString(0, "In Hard Fault Handler\r\n");
SEGGER_RTT_printf(0, "SCB->HFSR = 0x%08x\r\n", SCB->HFSR);
if ((SCB->HFSR & (1 << 30)) != 0)
{
SEGGER_RTT_WriteString(0, "Forced Hard Fault\r\n");
SEGGER_RTT_printf(0, "SCB->CFSR = 0x%08x\r\n", SCB->CFSR);
if ((SCB->CFSR & 0xFFFF0000) != 0)
{
printUsageErrorMsg(SCB->CFSR);
}
}
__ASM volatile("BKPT #01");
while (1)
{
};
}