Merge changes If50dcc0e,I17d591a5,I9c1cabda,Ib73d395b,I7e923b0d, ...
* changes:
Only schedule OnRun callbacks right after construction in aos
Split function scheduler out
Fix transmit timestamp logic in SimulatedNetworkBridge
Unit test for mismatched configs for server/client
Convert unreachable simulated network bridge code to CHECKs.
aos: Fix `--force_timestamp_loading` for single-node logs
Log, replay, and solve with transmit timestamps
Add boot info to NoncausalTimestampFilter debugging
Logger: Pipe the monotonic_remote_transmit_time through event loop
Remove unused kLogMessageAndDeliveryTime
Fix starter_test under msan
memory_mapped_queue: Use system_page_size
Logger: Define contract to record transmit time for reliable messages
Add note to static fbs Vector reserve() method
Add a test reproducing a log reading failure
Fix move ResizeableObject move constructor
Logger: Print solve number along with candidate solution for debug info
Call set_name() on more AOS timers
Fix crash in message_bridge_server
Fix typo in message_bridge_auth_client_lib.cc
Fix Python wheel generation
Fix LogReader destruction problem
Make doctests only compatible with x86_64
Fix possible data race in `aos/network/multinode_timestamp_filter.h`
Fix handling of empty C++ comments in JSON parsing
rename variables in aos Logger
Fix AOS logging when using non-EventLoop configuration
Add SendJson to AOS Sender
Add note on size units in file_operations.h
Reduce discrepancies between FlatbufferToJson versions
Reduce flakeness of shm_event_loop_test
aos: Make SetCurrentThreadAffinity errors a bit nicer
diff --git a/frc971/imu_fdcan/Dual_IMU/Core/Inc/main.h b/frc971/imu_fdcan/Dual_IMU/Core/Inc/main.h
index e2ab234..f4e0ee8 100644
--- a/frc971/imu_fdcan/Dual_IMU/Core/Inc/main.h
+++ b/frc971/imu_fdcan/Dual_IMU/Core/Inc/main.h
@@ -56,12 +56,63 @@
/* USER CODE BEGIN EFP */
// Different representations of the same four byte value. Simplifies conversion.
-union FourBytes {
+typedef union {
float decimal;
uint32_t four_bytes;
uint16_t two_bytes[2];
uint8_t byte[4];
-};
+} FourBytes;
+
+typedef enum { SPI_INIT, SPI_ZERO, SPI_START, SPI_RUN } SpiIn;
+
+typedef enum { SPI_READY, SPI_BUSY } SpiOut;
+
+typedef struct {
+ int16_t acc_x;
+ int16_t acc_y;
+ int16_t acc_z;
+ int16_t gyro_x;
+ int16_t gyro_y;
+ int16_t gyro_z;
+ int16_t temp;
+ int state;
+ int index;
+} DataRawInt16;
+
+typedef struct {
+ float acc_x;
+ float acc_y;
+ float acc_z;
+ float gyro_x;
+ float gyro_y;
+ float gyro_z;
+ float temp;
+} DataOutFloat;
+
+typedef struct {
+ uint32_t timestamp;
+ uint16_t can_counter;
+ uint16_t tdk_counter;
+ uint16_t uno_counter;
+ uint16_t due_counter;
+ float tdk_acc_x;
+ float tdk_acc_y;
+ float tdk_acc_z;
+ float tdk_gyro_x;
+ float tdk_gyro_y;
+ float tdk_gyro_z;
+ float murata_acc_x;
+ float murata_acc_y;
+ float murata_acc_z;
+ float murata_gyro_x;
+ float murata_gyro_y;
+ float murata_gyro_z;
+ uint8_t tdk_temp;
+ uint8_t uno_temp;
+ uint8_t due_temp;
+ uint8_t flags;
+} CanData;
+
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
@@ -95,6 +146,10 @@
#define T_VCP_TX_GPIO_Port GPIOC
#define T_VCP_RX_Pin GPIO_PIN_5
#define T_VCP_RX_GPIO_Port GPIOC
+#define PWM_RATE_Pin GPIO_PIN_0
+#define PWM_RATE_GPIO_Port GPIOB
+#define PWM_HEADING_Pin GPIO_PIN_1
+#define PWM_HEADING_GPIO_Port GPIOB
#define CS_UNO_Pin GPIO_PIN_12
#define CS_UNO_GPIO_Port GPIOB
#define SCK_UNO_Pin GPIO_PIN_13
@@ -129,6 +184,9 @@
#define FDCAN_STBY_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
+
+#define IMU_SAMPLES_PER_MS 3
+
/* USER CODE END Private defines */
#ifdef __cplusplus
diff --git a/frc971/imu_fdcan/Dual_IMU/Core/Inc/murata.h b/frc971/imu_fdcan/Dual_IMU/Core/Inc/murata.h
index a3cf626..19cddd9 100644
--- a/frc971/imu_fdcan/Dual_IMU/Core/Inc/murata.h
+++ b/frc971/imu_fdcan/Dual_IMU/Core/Inc/murata.h
@@ -15,10 +15,15 @@
#include <stdint.h>
#include <stdio.h>
+#include "math.h"
+
#define CONV_INT16_INT8_H(a) ((int8_t)(((a) >> 8) & 0xFF))
#define CONV_INT16_INT8_L(a) ((int8_t)(a & 0xFF))
+#define CONV_UINT8_INT16(a_H, a_L) (int16_t)((a_H << 8) | a_L)
#define CONV_UINT16_UINT8_H(a) ((uint8_t)(((a) >> 8) & 0xFF))
#define CONV_UINT16_UINT8_L(a) ((uint8_t)(a & 0xFF))
+#define CONV_UINT16_INT8_H(a) ((int8_t)(((a) >> 8) & 0xFF))
+#define CONV_UINT16_INT8_L(a) ((int8_t)(a & 0xFF))
#define GET_SPI_DATA_INT16(a) ((int16_t)(((a) >> 8) & 0xFFFF))
#define GET_SPI_DATA_UINT16(a) ((uint16_t)(((a) >> 8) & 0xFFFF))
@@ -26,7 +31,7 @@
#define GET_SPI_DATA_UINT8_L(a) ((uint8_t)((a >> 8) & 0xFF))
#define CHECK_RS_ERROR(a) (!(((a) >> 24) & 0x03))
#define MURATA_CONV_TEMP(a) (float)((a / 30.0f) + 25)
-#define MURATA_CONV_GYRO(a) (float)(a / 80.0f)
+#define MURATA_CONV_GYRO(a) (float)(a / 80.0f) * ((float)(M_PI) / 180.0f)
#define MURATA_CONV_ACC(a) (float)(a / 4905.0f)
// Define each operation as SPI 32-bit frame. Details in datasheet page 34
@@ -40,6 +45,11 @@
#define WRITE_FILTER_46HZ_ACC 0xE8022248 // Set 46 Hz filter
#define WRITE_EOI_BIT 0xE000025B
+#define MURATA_GYRO_FILTER_ADDR 0x36
+#define MURATA_GYRO_FILTER_300HZ 0x2424
+#define MURATA_ACC_FILTER_ADDR 0xE8
+#define MURATA_ACC_FILTER_300HZ 0x0444
+
#define READ_GYRO_X 0x040000F7
#define READ_GYRO_Y 0x0C0000FB
#define READ_GYRO_Z 0x040000F7
@@ -48,11 +58,6 @@
#define READ_ACC_Z 0x180000E5
#define READ_TEMP 0x1C0000E3
-#define READ_ACCELEROMETER_STATUS 0x4800009D
-#define READ_COMMON_STATUS_1 0x50000089
-#define READ_COMMON_STATUS_2 0x5400008F
-#define READ_RATE_STATUS_1 0x40000091
-#define READ_RATE_STATUS_2 0x44000097
#define READ_SUMMARY_STATUS 0x380000D5
#define READ_TRC_0 0x740000BF
#define READ_TRC_1 0x780000B5
@@ -81,8 +86,8 @@
int16_t gyro_x; // deg/s
int16_t gyro_y; // deg/s
int16_t gyro_z; // deg/s
- int16_t temp_due; // C
- int16_t temp_uno; // C
+ int16_t due_temp; // C
+ int16_t uno_temp; // C
} DataMurataRaw;
// Human readable sensor data
@@ -93,8 +98,8 @@
float gyro_x;
float gyro_y;
float gyro_z;
- float temp_due;
- float temp_uno;
+ float due_temp;
+ float uno_temp;
} DataMurata;
// Cross axis compensation values for fine tuning acc and gyro output
diff --git a/frc971/imu_fdcan/Dual_IMU/Core/Inc/stm32g4xx_it.h b/frc971/imu_fdcan/Dual_IMU/Core/Inc/stm32g4xx_it.h
index c320580..6b6817a 100644
--- a/frc971/imu_fdcan/Dual_IMU/Core/Inc/stm32g4xx_it.h
+++ b/frc971/imu_fdcan/Dual_IMU/Core/Inc/stm32g4xx_it.h
@@ -55,6 +55,10 @@
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
+void TIM1_UP_TIM16_IRQHandler(void);
+void SPI1_IRQHandler(void);
+void SPI2_IRQHandler(void);
+void SPI3_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
diff --git a/frc971/imu_fdcan/Dual_IMU/Core/Inc/tdk.h b/frc971/imu_fdcan/Dual_IMU/Core/Inc/tdk.h
index 4346810..6b29184 100644
--- a/frc971/imu_fdcan/Dual_IMU/Core/Inc/tdk.h
+++ b/frc971/imu_fdcan/Dual_IMU/Core/Inc/tdk.h
@@ -11,12 +11,19 @@
#ifndef INC_TDK_H_
#define INC_TDK_H_
-#define CONV_UINT8_INT16(a_H, a_L) (int16_t)((a_H << 8) | a_L)
+#include "math.h"
+
+// TDK Range
+#define TDK_ACC_MAG_MAX (float)(16) // +/- 16 g's
+#define TDK_GYRO_MAG_MAX \
+ (float)(2000.0f * \
+ ((float)(M_PI) / 180.0f)) // +/- 2000 dps to rad/s ~85 rad/s
// Convert raw sensor data to human readable format
-#define TDK_CONV_TEMP(a) (float)((a / 326.8f) + 25) // output in Celsius
-#define TDK_CONV_GYRO(a) (float)(a / 16.4f) // output in deg/s
-#define TDK_CONV_ACC(a) (float)(a / 2048.0f) // output in g
+#define TDK_CONV_TEMP(a) (float)((a / 326.8f) + 25.0f) // output in Celsius
+#define TDK_CONV_GYRO(a) \
+ (float)(a / 16.4f) * ((float)(M_PI) / 180.0f) // output in deg/s
+#define TDK_CONV_ACC(a) (float)(a / 2048.0f) // output in g
// Register map
#define SMPLRT_DIV 0x19
@@ -41,6 +48,7 @@
#define GYRO_ZOUT_L 0x48
#define USER_CTRL 0x6A
#define PWR_MGMT_1 0x6B
+#define PWR_MGMT_2 0x6C
#define FIFO_COUNT_H 0x72
#define FIFO_COUNT_L 0x73
#define FIFO_R_W 0x74
@@ -63,6 +71,17 @@
uint8_t temp_H;
} DataTdkRaw;
+// Combined version of raw data
+typedef struct {
+ int16_t acc_x;
+ int16_t acc_y;
+ int16_t acc_z;
+ int16_t gyro_x;
+ int16_t gyro_y;
+ int16_t gyro_z;
+ int16_t temp;
+} DataTdkRawCombined;
+
// Human readable sensor data
typedef struct {
float acc_x; // g
diff --git a/frc971/imu_fdcan/Dual_IMU/Core/Src/main.c b/frc971/imu_fdcan/Dual_IMU/Core/Src/main.c
index 98b61d2..c0758f8 100644
--- a/frc971/imu_fdcan/Dual_IMU/Core/Src/main.c
+++ b/frc971/imu_fdcan/Dual_IMU/Core/Src/main.c
@@ -24,6 +24,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include "murata.h"
#include "tdk.h"
@@ -36,8 +37,6 @@
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
-#define MURATA_ACC_FILTER WRITE_FILTER_46HZ_ACC
-#define MURATA_GYRO_FILTER WRITE_FILTER_46HZ_GYRO
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
@@ -54,6 +53,8 @@
SPI_HandleTypeDef hspi2;
SPI_HandleTypeDef hspi3;
+TIM_HandleTypeDef htim1;
+TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
UART_HandleTypeDef huart1;
@@ -75,13 +76,35 @@
FDCAN_FilterTypeDef sFilterConfig;
FDCAN_TxHeaderTypeDef tx_header;
+FDCAN_RxHeaderTypeDef rx_header;
static CrossAxisCompMurata
cac_murata; // Cross-axis compensation. Details on datasheet page 11
-static DataMurataRaw data_murata_raw;
static DataMurata data_murata;
-static DataTdkRaw data_tdk_raw;
static DataTdk data_tdk;
+static uint8_t can_tx[64];
+static int can_tx_packet_counter;
+static CanData can_out;
+static int timer_index;
+
+static DataMurata murata_averaged;
+static DataTdk tdk_averaged;
+
+static DataRawInt16 uno_data[IMU_SAMPLES_PER_MS];
+static DataRawInt16 due_data[IMU_SAMPLES_PER_MS];
+static DataRawInt16 tdk_data[IMU_SAMPLES_PER_MS];
+
+static SpiOut uno_state;
+static SpiOut due_state;
+static SpiOut tdk_state;
+
+static uint8_t spi1_rx[2];
+static uint8_t spi1_tx[2];
+static FourBytes spi2_rx;
+static FourBytes spi2_tx;
+static FourBytes spi3_rx;
+static FourBytes spi3_tx;
+static FourBytes spi_murata_rx;
/* USER CODE END PV */
@@ -96,10 +119,12 @@
static void MX_USART1_UART_Init(void);
static void MX_TIM3_Init(void);
static void MX_USB_PCD_Init(void);
+static void MX_TIM2_Init(void);
+static void MX_TIM1_Init(void);
/* USER CODE BEGIN PFP */
static void EnableLeds(void);
-static void EnableSpiTdk(void);
+static void PowerTdk(void);
static void ConvertEndianMurata(uint8_t *result, uint32_t original);
static uint8_t MurataCRC8(uint8_t bit_value,
uint8_t redundancy); // For checksum calculation.
@@ -114,12 +139,19 @@
static uint8_t SendSpiTdk(uint8_t address, uint8_t data, bool read);
static bool InitMurata(void);
static void InitTdk(void);
-static void ReadDataMurata(void);
-static void ReadDataTdk(void);
-static void ConvertDataMurata(void);
-static void ConvertDataTdk(void);
-static void InitCan(FDCAN_TxHeaderTypeDef *tx_header, uint8_t id);
-
+static void InitCan(FDCAN_TxHeaderTypeDef *tx_header, uint32_t id);
+static void PWMSend(TIM_HandleTypeDef *htim, uint32_t channel, float data);
+static void ConstructCanfdPacket(uint8_t *tx, DataMurata *murata, DataTdk *tdk);
+static void AverageData(void);
+static void ComposeData(void);
+static void RealignData(void);
+static void SpiReadIt(SPI_HandleTypeDef *hspix, uint32_t reg);
+static void SpiCsStart(SPI_HandleTypeDef *hspix);
+static void SpiCsEnd(SPI_HandleTypeDef *hspix);
+static void SpiTdk(DataRawInt16 *data, SPI_HandleTypeDef *hspix, SpiOut *res,
+ SpiIn call);
+static void SpiMurata(DataRawInt16 *data, SPI_HandleTypeDef *hspix, SpiOut *res,
+ SpiIn call);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
@@ -163,12 +195,19 @@
MX_USART1_UART_Init();
MX_TIM3_Init();
MX_USB_PCD_Init();
+ MX_TIM2_Init();
+ MX_TIM1_Init();
/* USER CODE BEGIN 2 */
- EnableLeds(); // Set LEDs to red
- InitTdk();
- InitMurata();
- InitCan(&tx_header, 0xAA);
+ EnableLeds(); // Set LEDs to red
+ InitCan(&tx_header, 0x01); // Initialize the CAN module
+ InitMurata(); // Run the Murata power up sequence (see pg 30 of datasheet)
+ InitTdk(); // Run the TDK power up sequence (see pg 22 of datasheet)
+ HAL_TIM_Base_Start_IT(&htim2); // Start 1 us timer
+ HAL_TIM_Base_Start_IT(&htim1); // Start 1 ms timer
+
+ HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_3);
+ HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_4);
/* USER CODE END 2 */
@@ -179,30 +218,6 @@
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
- ReadDataMurata();
- ConvertDataMurata();
- printf(
- "MUR IMU:\tX ACC: %.8f \tY ACC: %.8f \tZ ACC: %.8f \tX GYRO: %.8f \tY "
- "GYRO: %.8f \tZ GYRO: %.8f \n\r",
- data_murata.acc_x, data_murata.acc_y, data_murata.acc_z,
- data_murata.gyro_x, data_murata.gyro_y, data_murata.gyro_z);
-
- ReadDataTdk();
- ConvertDataTdk();
- printf(
- "TDK IMU:\t\tX ACC: %.8f \tY ACC: %.8f \tZ ACC: %.8f \tX GYRO: %.8f "
- "\tY GYRO: %.8f \tZ GYRO: %.8f \n\r",
- data_tdk.acc_x, data_tdk.acc_y, data_tdk.acc_z, data_tdk.gyro_x,
- data_tdk.gyro_y, data_tdk.gyro_z);
-
- uint8_t tx_data[8] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
-
- if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &tx_header, tx_data) !=
- HAL_OK) {
- Error_Handler();
- }
-
- HAL_Delay(100);
}
/* USER CODE END 3 */
}
@@ -453,6 +468,86 @@
}
/**
+ * @brief TIM1 Initialization Function
+ * @param None
+ * @retval None
+ */
+static void MX_TIM1_Init(void) {
+ /* USER CODE BEGIN TIM1_Init 0 */
+
+ /* USER CODE END TIM1_Init 0 */
+
+ TIM_ClockConfigTypeDef sClockSourceConfig = {0};
+ TIM_MasterConfigTypeDef sMasterConfig = {0};
+
+ /* USER CODE BEGIN TIM1_Init 1 */
+
+ /* USER CODE END TIM1_Init 1 */
+ htim1.Instance = TIM1;
+ htim1.Init.Prescaler = 168 - 1;
+ htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
+ htim1.Init.Period = 333;
+ htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ htim1.Init.RepetitionCounter = 0;
+ htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
+ if (HAL_TIM_Base_Init(&htim1) != HAL_OK) {
+ Error_Handler();
+ }
+ sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
+ if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) {
+ Error_Handler();
+ }
+ sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
+ sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
+ sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+ if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) {
+ Error_Handler();
+ }
+ /* USER CODE BEGIN TIM1_Init 2 */
+
+ /* USER CODE END TIM1_Init 2 */
+}
+
+/**
+ * @brief TIM2 Initialization Function
+ * @param None
+ * @retval None
+ */
+static void MX_TIM2_Init(void) {
+ /* USER CODE BEGIN TIM2_Init 0 */
+
+ /* USER CODE END TIM2_Init 0 */
+
+ TIM_ClockConfigTypeDef sClockSourceConfig = {0};
+ TIM_MasterConfigTypeDef sMasterConfig = {0};
+
+ /* USER CODE BEGIN TIM2_Init 1 */
+
+ /* USER CODE END TIM2_Init 1 */
+ htim2.Instance = TIM2;
+ htim2.Init.Prescaler = 168 - 1;
+ htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
+ htim2.Init.Period = 4.294967295E9;
+ htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
+ if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
+ Error_Handler();
+ }
+ sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
+ if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
+ Error_Handler();
+ }
+ sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
+ sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+ if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {
+ Error_Handler();
+ }
+ /* USER CODE BEGIN TIM2_Init 2 */
+
+ /* USER CODE END TIM2_Init 2 */
+}
+
+/**
* @brief TIM3 Initialization Function
* @param None
* @retval None
@@ -470,9 +565,9 @@
/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
- htim3.Init.Prescaler = 2563;
+ htim3.Init.Prescaler = 24 - 1;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim3.Init.Period = 65535;
+ htim3.Init.Period = 35000;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK) {
@@ -678,7 +773,7 @@
HAL_GPIO_WritePin(GPIOC, LED2_RED_Pin, GPIO_PIN_RESET);
}
-static void EnableSpiTdk(void) {
+static void PowerTdk(void) {
// TDK_PWR_EN starts high, must be set low before reading
HAL_GPIO_WritePin(TDK_PWR_EN_GPIO_Port, TDK_PWR_EN_Pin, GPIO_PIN_RESET);
// TDK_EN starts high, must be set low after a delay from TDK_PWR_EN
@@ -728,7 +823,7 @@
static uint32_t MakeSpiMsgMurata(uint8_t address, uint16_t data) {
// Constructs SPI read/write frame
// Details on datasheet page 32-34
- uint32_t message = (uint32_t)((((address << 2) | 0x01) << 24) | data << 8);
+ uint32_t message = (uint32_t)(((address << 2) << 24) | data << 8);
uint8_t redundancy = GetChecksumMurata(message);
return (uint32_t)(message | redundancy);
}
@@ -740,9 +835,9 @@
static uint32_t TransmitSpiMurata(uint32_t value, GPIO_TypeDef *cs_port,
uint16_t cs_pin, SPI_HandleTypeDef *hspix) {
- union FourBytes rx_data_raw;
- union FourBytes rx_data;
- union FourBytes tx_data;
+ FourBytes rx_data_raw;
+ FourBytes rx_data;
+ FourBytes tx_data;
ConvertEndianMurata(tx_data.byte, value);
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(hspix, tx_data.byte, rx_data_raw.byte,
@@ -772,10 +867,6 @@
return spi_rx[0];
}
-static uint8_t ReadSpiTdk(uint8_t address) {
- return SendSpiTdk(address, 0x00, true);
-}
-
static bool InitMurata(void) {
int num_attempts = 0;
uint32_t response_due = 0;
@@ -794,6 +885,13 @@
HAL_Delay(25);
+ SendSpiDue(MakeSpiReadMsgMurata(ACC_DC1_ADDRESS)); // cxx_cxy address
+
+ SendSpiDue(WRITE_OP_MODE_NORMAL);
+ SendSpiDue(WRITE_OP_MODE_NORMAL);
+ SendSpiUno(WRITE_OP_MODE_NORMAL);
+ HAL_Delay(70);
+
SendSpiDue(WRITE_MODE_ASM_010);
SendSpiDue(READ_MODE);
SendSpiDue(WRITE_MODE_ASM_001);
@@ -864,8 +962,9 @@
SendSpiUno(WRITE_OP_MODE_NORMAL);
HAL_Delay(70);
- SendSpiUno(MURATA_GYRO_FILTER);
- SendSpiUno(MURATA_ACC_FILTER);
+ SendSpiUno(
+ MakeSpiMsgMurata(MURATA_GYRO_FILTER_ADDR, MURATA_GYRO_FILTER_300HZ));
+ SendSpiUno(MakeSpiMsgMurata(MURATA_ACC_FILTER_ADDR, MURATA_ACC_FILTER_300HZ));
HAL_GPIO_WritePin(RESET_DUE_GPIO_Port, RESET_DUE_Pin,
GPIO_PIN_RESET); // Reset DUE
@@ -877,7 +976,8 @@
SendSpiDue(WRITE_OP_MODE_NORMAL);
HAL_Delay(1);
- SendSpiDue(MURATA_GYRO_FILTER);
+ SendSpiDue(
+ MakeSpiMsgMurata(MURATA_GYRO_FILTER_ADDR, MURATA_GYRO_FILTER_300HZ));
for (num_attempts = 0; num_attempts < 2; num_attempts++) {
HAL_Delay(405);
@@ -915,9 +1015,12 @@
SendSpiUno(WRITE_OP_MODE_NORMAL);
HAL_Delay(50);
- SendSpiUno(MURATA_GYRO_FILTER);
- SendSpiUno(MURATA_ACC_FILTER);
- SendSpiDue(MURATA_GYRO_FILTER);
+ SendSpiUno(
+ MakeSpiMsgMurata(MURATA_GYRO_FILTER_ADDR, MURATA_GYRO_FILTER_300HZ));
+ SendSpiUno(
+ MakeSpiMsgMurata(MURATA_ACC_FILTER_ADDR, MURATA_ACC_FILTER_300HZ));
+ SendSpiDue(
+ MakeSpiMsgMurata(MURATA_GYRO_FILTER_ADDR, MURATA_GYRO_FILTER_300HZ));
HAL_Delay(45);
} else {
break;
@@ -931,31 +1034,216 @@
return true;
}
-// Todo (Zach): separate the steps of reading data and realigning axis
-static void ReadDataMurata(void) {
- SendSpiUno(READ_ACC_Z);
- data_murata_raw.acc_z = -GET_SPI_DATA_INT16(SendSpiUno(READ_ACC_X));
- data_murata_raw.acc_y = GET_SPI_DATA_INT16(SendSpiUno(READ_ACC_Y));
- data_murata_raw.acc_x = GET_SPI_DATA_INT16(SendSpiUno(READ_GYRO_X));
- data_murata_raw.gyro_y = -GET_SPI_DATA_INT16(SendSpiUno(READ_TEMP));
- data_murata_raw.temp_uno = GET_SPI_DATA_INT16(SendSpiUno(READ_ACC_Z));
+static void InitTdk(void) {
+ // Power up sequence. See datasheet p22 for details
+ // The chip must receive power prior to SPI
+ PowerTdk();
- SendSpiDue(READ_GYRO_Z);
- data_murata_raw.gyro_z = GET_SPI_DATA_INT16(SendSpiDue(READ_GYRO_Y));
- data_murata_raw.gyro_x = -GET_SPI_DATA_INT16(SendSpiDue(READ_TEMP));
- data_murata_raw.temp_due = GET_SPI_DATA_INT16(SendSpiDue(READ_GYRO_Z));
+ // Send 0x81 to PWR_MGMT to initialize SPI
+ SendSpiTdk(PWR_MGMT_1, 0x81, false);
+ HAL_Delay(100);
+
+ // Setting the sample rates for TDK
+ SendSpiTdk(USER_CTRL, 0x55, false);
+ SendSpiTdk(ACCEL_CONFIG, 0x18, false);
+ SendSpiTdk(ACCEL_CONFIG_2, 0x08, false);
+ SendSpiTdk(GYRO_CONFIG, 0x1A, false);
+ SendSpiTdk(FIFO_EN, 0x00, false);
+ SendSpiTdk(CONFIG, 0x00, false);
+ SendSpiTdk(SMPLRT_DIV, 0x00, false);
}
-static void ConvertDataMurata(void) {
- data_murata.acc_x = MURATA_CONV_ACC(data_murata_raw.acc_x);
- data_murata.acc_y = MURATA_CONV_ACC(data_murata_raw.acc_y);
- data_murata.acc_z = MURATA_CONV_ACC(data_murata_raw.acc_z);
- data_murata.gyro_x = MURATA_CONV_GYRO(data_murata_raw.gyro_x);
- data_murata.gyro_y = MURATA_CONV_GYRO(data_murata_raw.gyro_y);
- data_murata.gyro_z = MURATA_CONV_GYRO(data_murata_raw.gyro_z);
- data_murata.temp_uno = MURATA_CONV_TEMP(data_murata_raw.temp_uno);
- data_murata.temp_due = MURATA_CONV_TEMP(data_murata_raw.temp_due);
+static void InitCan(FDCAN_TxHeaderTypeDef *tx_header, uint32_t id) {
+ // Initialize the Header
+ tx_header->Identifier = id;
+ tx_header->IdType = FDCAN_STANDARD_ID;
+ tx_header->TxFrameType = FDCAN_DATA_FRAME;
+ tx_header->DataLength = FDCAN_DLC_BYTES_8;
+ tx_header->ErrorStateIndicator = FDCAN_ESI_ACTIVE;
+ tx_header->BitRateSwitch = FDCAN_BRS_OFF;
+ tx_header->FDFormat = FDCAN_CLASSIC_CAN;
+ tx_header->TxEventFifoControl = FDCAN_NO_TX_EVENTS;
+ tx_header->MessageMarker = 0x0; // Ignore because FDCAN_NO_TX_EVENTS
+ // Pull standby pin low
+ HAL_GPIO_WritePin(FDCAN_STBY_GPIO_Port, FDCAN_STBY_Pin, GPIO_PIN_RESET);
+
+ // Start the FDCAN module
+ if (HAL_FDCAN_Start(&hfdcan2) != HAL_OK) {
+ Error_Handler();
+ }
+
+ // Initialize can_out to zeros
+ memset(&can_out, 0, sizeof(can_out));
+}
+
+static void PWMSend(TIM_HandleTypeDef *htim, uint32_t channel, float data) {
+ if (htim == &htim3) {
+ // 10% pwm == min, 90% pwm == max
+ float pwm_period = (float)(htim->Init.Period);
+ float range;
+ float scale;
+ float translated;
+ uint32_t result;
+
+ switch (channel) {
+ case TIM_CHANNEL_3:
+ // Sends TDK Z-gyro data over PWM_Rate port
+ range = 2 * TDK_GYRO_MAG_MAX;
+ scale = (pwm_period * .8f) / range;
+ translated = data + range * .5f;
+ result = (uint32_t)(scale * translated + pwm_period * .1f);
+ if (result < pwm_period * .1f) {
+ result = pwm_period * .1f;
+ }
+ if (result > pwm_period * .9f) {
+ result = pwm_period * .9f;
+ }
+ TIM3->CCR3 = result;
+ break;
+
+ case TIM_CHANNEL_4:
+ // Unused PWM_Heading port
+ // TODO: (Zach) figure out if we keep it with the
+ // same as CH3 or if we add something else
+ range = 2 * TDK_GYRO_MAG_MAX;
+ scale = (pwm_period * .8f) / range;
+ translated = data + range * .5f;
+ result = (uint32_t)(scale * translated + pwm_period * .1f);
+ if (result < pwm_period * .1f) {
+ result = pwm_period * .1f;
+ }
+ if (result > pwm_period * .9f) {
+ result = pwm_period * .9f;
+ }
+ TIM3->CCR4 = result;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/* CAN_FD Tx data packet specs:
+ * https://docs.google.com/document/d/12AJUruW7DZ2pIrDzTyPC0qqFoia4QOSVlax6Jd7m4H0
+ */
+
+static void ConstructCanfdPacket(uint8_t *tx, DataMurata *murata,
+ DataTdk *tdk) {
+ // Clear the CAN packet
+ memset(tx, 0, 64 * sizeof(*tx));
+
+ // Write in the struct data
+ can_out.tdk_acc_x = tdk->acc_x;
+ can_out.tdk_acc_y = tdk->acc_y;
+ can_out.tdk_acc_z = tdk->acc_z;
+ can_out.tdk_gyro_x = tdk->gyro_x;
+ can_out.tdk_gyro_y = tdk->gyro_y;
+ can_out.tdk_gyro_z = tdk->gyro_z;
+
+ can_out.murata_acc_x = murata->acc_x;
+ can_out.murata_acc_y = murata->acc_y;
+ can_out.murata_acc_z = murata->acc_z;
+ can_out.murata_gyro_x = murata->gyro_x;
+ can_out.murata_gyro_y = murata->gyro_y;
+ can_out.murata_gyro_z = murata->gyro_z;
+
+ if (tdk->temp < 0) {
+ can_out.tdk_temp = 0;
+ } else if (tdk->temp > 255) {
+ can_out.tdk_temp = 255;
+ } else {
+ can_out.tdk_temp = (uint8_t)(tdk->temp);
+ }
+
+ if (murata->uno_temp < 0) {
+ can_out.uno_temp = 0;
+ } else if (murata->uno_temp > 255) {
+ can_out.uno_temp = 255;
+ } else {
+ can_out.uno_temp = (uint8_t)(murata->uno_temp);
+ }
+
+ if (murata->due_temp < 0) {
+ can_out.due_temp = 0;
+ } else if (murata->due_temp > 255) {
+ can_out.due_temp = 255;
+ } else {
+ can_out.due_temp = (uint8_t)(murata->due_temp);
+ }
+
+ can_out.timestamp = __HAL_TIM_GetCounter(&htim2);
+
+ memcpy(&tx[0], &can_out, sizeof(can_out));
+}
+
+static void AverageData(void) {
+ // Clear the float data fields
+ memset(&tdk_averaged, 0, sizeof(tdk_averaged));
+ memset(&murata_averaged, 0, sizeof(murata_averaged));
+
+ for (int i = 0; i < IMU_SAMPLES_PER_MS; i++) {
+ tdk_averaged.acc_x += tdk_data[i].acc_x;
+ tdk_averaged.acc_y += tdk_data[i].acc_y;
+ tdk_averaged.acc_z += tdk_data[i].acc_z;
+ tdk_averaged.gyro_x += tdk_data[i].gyro_x;
+ tdk_averaged.gyro_y += tdk_data[i].gyro_y;
+ tdk_averaged.gyro_z += tdk_data[i].gyro_z;
+ tdk_averaged.temp += tdk_data[i].temp;
+
+ murata_averaged.acc_x += uno_data[i].acc_x;
+ murata_averaged.acc_y += uno_data[i].acc_y;
+ murata_averaged.acc_z += uno_data[i].acc_z;
+ murata_averaged.gyro_x += uno_data[i].gyro_x;
+ murata_averaged.gyro_y += due_data[i].gyro_y;
+ murata_averaged.gyro_z += due_data[i].gyro_z;
+ murata_averaged.uno_temp += uno_data[i].temp;
+ murata_averaged.due_temp += due_data[i].temp;
+ }
+
+ tdk_averaged.acc_x /= IMU_SAMPLES_PER_MS;
+ tdk_averaged.acc_y /= IMU_SAMPLES_PER_MS;
+ tdk_averaged.acc_z /= IMU_SAMPLES_PER_MS;
+ tdk_averaged.gyro_x /= IMU_SAMPLES_PER_MS;
+ tdk_averaged.gyro_y /= IMU_SAMPLES_PER_MS;
+ tdk_averaged.gyro_z /= IMU_SAMPLES_PER_MS;
+ tdk_averaged.temp /= IMU_SAMPLES_PER_MS;
+
+ murata_averaged.acc_x /= IMU_SAMPLES_PER_MS;
+ murata_averaged.acc_y /= IMU_SAMPLES_PER_MS;
+ murata_averaged.acc_z /= IMU_SAMPLES_PER_MS;
+ murata_averaged.gyro_x /= IMU_SAMPLES_PER_MS;
+ murata_averaged.gyro_y /= IMU_SAMPLES_PER_MS;
+ murata_averaged.gyro_z /= IMU_SAMPLES_PER_MS;
+ murata_averaged.uno_temp /= IMU_SAMPLES_PER_MS;
+ murata_averaged.due_temp /= IMU_SAMPLES_PER_MS;
+}
+
+static void ComposeData(void) {
+ // Clear the float data fields
+ memset(&data_tdk, 0, sizeof(data_tdk));
+ memset(&data_murata, 0, sizeof(data_murata));
+
+ // Assign the converted binary
+ data_tdk.acc_x = TDK_CONV_ACC(tdk_averaged.acc_x);
+ data_tdk.acc_y = TDK_CONV_ACC(tdk_averaged.acc_y);
+ data_tdk.acc_z = TDK_CONV_ACC(tdk_averaged.acc_z);
+ data_tdk.gyro_x = TDK_CONV_GYRO(tdk_averaged.gyro_x);
+ data_tdk.gyro_y = TDK_CONV_GYRO(tdk_averaged.gyro_y);
+ data_tdk.gyro_z = TDK_CONV_GYRO(tdk_averaged.gyro_z);
+ data_tdk.temp = TDK_CONV_TEMP(tdk_averaged.temp);
+
+ data_murata.acc_x = MURATA_CONV_ACC(murata_averaged.acc_x);
+ data_murata.acc_y = MURATA_CONV_ACC(murata_averaged.acc_y);
+ data_murata.acc_z = MURATA_CONV_ACC(murata_averaged.acc_z);
+ data_murata.gyro_x = MURATA_CONV_GYRO(murata_averaged.gyro_x);
+ data_murata.gyro_y = MURATA_CONV_GYRO(murata_averaged.gyro_y);
+ data_murata.gyro_z = MURATA_CONV_GYRO(murata_averaged.gyro_z);
+ data_murata.uno_temp = MURATA_CONV_TEMP(murata_averaged.uno_temp);
+ data_murata.due_temp = MURATA_CONV_TEMP(murata_averaged.due_temp);
+
+ // Apply the murata cross-axis compensation
data_murata.acc_x = (cac_murata.bxx * data_murata.acc_x) +
(cac_murata.bxy * data_murata.acc_y) +
(cac_murata.bxz * data_murata.acc_z);
@@ -977,98 +1265,363 @@
(cac_murata.czz * data_murata.gyro_z);
}
-static void ReadDataTdk(void) {
- data_tdk_raw.acc_x_H = ReadSpiTdk(ACCEL_XOUT_H);
- data_tdk_raw.acc_x_L = ReadSpiTdk(ACCEL_XOUT_L);
- data_tdk_raw.acc_y_H = ReadSpiTdk(ACCEL_YOUT_H);
- data_tdk_raw.acc_y_L = ReadSpiTdk(ACCEL_YOUT_L);
- data_tdk_raw.acc_z_H = ReadSpiTdk(ACCEL_ZOUT_H);
- data_tdk_raw.acc_z_L = ReadSpiTdk(ACCEL_ZOUT_L);
- data_tdk_raw.gyro_x_H = ReadSpiTdk(GYRO_XOUT_H);
- data_tdk_raw.gyro_x_L = ReadSpiTdk(GYRO_XOUT_L);
- data_tdk_raw.gyro_y_H = ReadSpiTdk(GYRO_YOUT_H);
- data_tdk_raw.gyro_y_L = ReadSpiTdk(GYRO_YOUT_L);
- data_tdk_raw.gyro_z_H = ReadSpiTdk(GYRO_ZOUT_H);
- data_tdk_raw.gyro_z_L = ReadSpiTdk(GYRO_ZOUT_L);
- data_tdk_raw.temp_H = ReadSpiTdk(TEMP_OUT_H);
- data_tdk_raw.temp_L = ReadSpiTdk(TEMP_OUT_L);
+static void RealignData(void) {
+ // Rotate the axis based on observed behavior
+ float f = data_tdk.acc_x;
+ data_tdk.acc_x = -data_tdk.acc_y;
+ data_tdk.acc_y = -f;
+ f = data_tdk.gyro_x;
+ data_tdk.acc_z = -data_tdk.acc_z;
+ data_tdk.gyro_x = -data_tdk.gyro_y;
+ data_tdk.gyro_y = -f;
+ data_tdk.gyro_z = -data_tdk.gyro_z;
+
+ f = data_murata.acc_x;
+ data_murata.acc_x = -data_murata.acc_y;
+ data_murata.acc_y = -f;
+ f = data_murata.gyro_x;
+ data_murata.gyro_x = -data_murata.gyro_y;
+ data_murata.gyro_y = -f;
}
-static void ConvertDataTdk(void) {
- data_tdk.acc_x = TDK_CONV_ACC(
- CONV_UINT8_INT16(data_tdk_raw.acc_y_H, data_tdk_raw.acc_y_L));
- data_tdk.acc_y = TDK_CONV_ACC(
- CONV_UINT8_INT16(data_tdk_raw.acc_x_H, data_tdk_raw.acc_x_L));
- data_tdk.acc_z = TDK_CONV_ACC(
- CONV_UINT8_INT16(data_tdk_raw.acc_z_H, data_tdk_raw.acc_z_L));
- data_tdk.gyro_x = -TDK_CONV_GYRO(
- CONV_UINT8_INT16(data_tdk_raw.gyro_y_H, data_tdk_raw.gyro_y_L));
- data_tdk.gyro_y = -TDK_CONV_GYRO(
- CONV_UINT8_INT16(data_tdk_raw.gyro_x_H, data_tdk_raw.gyro_x_L));
- data_tdk.gyro_z = -TDK_CONV_GYRO(
- CONV_UINT8_INT16(data_tdk_raw.gyro_z_H, data_tdk_raw.gyro_z_L));
- data_tdk.temp =
- TDK_CONV_TEMP(CONV_UINT8_INT16(data_tdk_raw.temp_H, data_tdk_raw.temp_L));
+// Read SPI in interrupt mode
+static void SpiReadIt(SPI_HandleTypeDef *hspix, uint32_t reg) {
+ if (hspix == &hspi1) {
+ spi1_tx[0] = 0x00;
+ spi1_tx[1] = (uint8_t)(reg & 0xFF) | 0x80;
+ memset(spi1_rx, 0, sizeof(*spi1_rx));
+
+ HAL_SPI_TransmitReceive_IT(hspix, spi1_tx, spi1_rx, sizeof(spi1_tx) / 2);
+ } else if (hspix == &hspi2 || hspix == &hspi3) {
+ ConvertEndianMurata((hspix == &hspi2) ? (spi2_tx.byte) : (spi3_tx.byte),
+ reg);
+ memset((hspix == &hspi2) ? spi2_rx.byte : spi3_rx.byte, 0, 4);
+
+ HAL_SPI_TransmitReceive_IT(
+ hspix, (hspix == &hspi2) ? spi2_tx.byte : spi3_tx.byte,
+ (hspix == &hspi2) ? spi2_rx.byte : spi3_rx.byte, 2);
+ }
}
-static void InitTdk(void) {
- // The chip must receive power prior to SPI
- EnableSpiTdk();
-
- // Send 0x81 to PWR_MGMT to initialize SPI
- SendSpiTdk(PWR_MGMT_1, 0x81, false);
- HAL_Delay(100);
-
- // Setting the sample rates for TDK
- SendSpiTdk(SMPLRT_DIV, 0x00, false);
- SendSpiTdk(CONFIG, 0x00, false);
- SendSpiTdk(GYRO_CONFIG, 0x1A, false);
- SendSpiTdk(ACCEL_CONFIG, 0x18, false);
- SendSpiTdk(ACCEL_CONFIG_2, 0x08, false);
- SendSpiTdk(FIFO_EN, 0xF8, false);
- SendSpiTdk(USER_CTRL, 0x55, false);
+static void SpiCsStart(SPI_HandleTypeDef *hspix) {
+ if (hspix == &hspi1) {
+ HAL_GPIO_WritePin(CS_TDK_ST_GPIO_Port, CS_TDK_ST_Pin,
+ GPIO_PIN_RESET); // CS low at start of transmission
+ } else if (hspix == &hspi2) {
+ HAL_GPIO_WritePin(CS_UNO_GPIO_Port, CS_UNO_Pin,
+ GPIO_PIN_RESET); // CS low at start of transmission
+ } else if (hspix == &hspi3) {
+ HAL_GPIO_WritePin(CS_DUE_GPIO_Port, CS_DUE_Pin,
+ GPIO_PIN_RESET); // CS low at start of transmission
+ }
}
-/* CAN_FD Tx data packet:
- *
- * BYTES Contents Bits of content
- * [0..3] murata_acc_x [0..31]
- * [4..7] murata_acc_y [0..31]
- * [8..11] murata_acc_z [0..31]
- * [12..15] murata_gyro_x [0..31]
- * [16..19] murata_gyro_y [0..31]
- * [20..23] murata_gyro_z [0..31]
- * [24..27] murata_due_temp [0..31]
- * [28..31] murata_uno_temp [0..31]
- * [32..35] tdk_acc_x [0..31]
- * [36..39] tdk_acc_y [0..31]
- * [40..43] tdk_acc_z [0..31]
- * [44..47] tdk_gyro_x [0..31]
- * [48..51] tdk_gyro_y [0..31]
- * [52..55] tdk_gyro_z [0..31]
- * [56..59] tdk_temp [0..31]
- * [60..63] murata_acc_x [0..31]
- *
- */
+static void SpiCsEnd(SPI_HandleTypeDef *hspix) {
+ if (hspix == &hspi1) {
+ HAL_GPIO_WritePin(CS_TDK_ST_GPIO_Port, CS_TDK_ST_Pin,
+ GPIO_PIN_SET); // CS high at end of transmission
+ } else if (hspix == &hspi2) {
+ HAL_GPIO_WritePin(CS_UNO_GPIO_Port, CS_UNO_Pin,
+ GPIO_PIN_SET); // CS high at end of transmission
+ } else if (hspix == &hspi3) {
+ HAL_GPIO_WritePin(CS_DUE_GPIO_Port, CS_DUE_Pin,
+ GPIO_PIN_SET); // CS high at end of transmission
+ }
+}
-static void InitCan(FDCAN_TxHeaderTypeDef *tx_header, uint8_t id) {
- // Initialize the Header
- tx_header->Identifier = id;
- tx_header->IdType = FDCAN_STANDARD_ID;
- tx_header->TxFrameType = FDCAN_DATA_FRAME;
- tx_header->DataLength = FDCAN_DLC_BYTES_8;
- tx_header->ErrorStateIndicator = FDCAN_ESI_ACTIVE;
- tx_header->BitRateSwitch = FDCAN_BRS_OFF;
- tx_header->FDFormat = FDCAN_CLASSIC_CAN;
- tx_header->TxEventFifoControl = FDCAN_NO_TX_EVENTS;
- tx_header->MessageMarker = 0x0; // Ignore because FDCAN_NO_TX_EVENTS
+static void SpiTdk(DataRawInt16 *data, SPI_HandleTypeDef *hspix, SpiOut *res,
+ SpiIn call) {
+ switch (call) {
+ case SPI_INIT:
+ InitTdk();
+ break;
+ case SPI_ZERO:
+ memset(data, 0, IMU_SAMPLES_PER_MS * sizeof(*data));
+ break;
+ case SPI_START:
+ data[timer_index].state = 0;
+ data[timer_index].index = 0;
+ *res = SPI_READY;
+ break;
- // Pull standby pin low
- HAL_GPIO_WritePin(FDCAN_STBY_GPIO_Port, FDCAN_STBY_Pin, GPIO_PIN_RESET);
+ case SPI_RUN:
+ *res = SPI_BUSY;
- // Start the FDCAN module
- if (HAL_FDCAN_Start(&hfdcan2) != HAL_OK) {
- Error_Handler();
+ SpiCsStart(hspix);
+
+ switch (data[timer_index].state) {
+ case 0:
+ SpiReadIt(hspix, ACCEL_XOUT_H); // REG + acc_x_h
+ break;
+ case 1:
+ SpiReadIt(hspix, 0x00); // acc_x_l + acc_y_h
+ break;
+ case 2:
+ SpiReadIt(hspix, 0x00); // acc_y_l + acc_z_h
+ break;
+ case 3:
+ SpiReadIt(hspix, 0x00); // acc_z_l + temp_h
+ break;
+ case 4:
+ SpiReadIt(hspix, 0x00); // temp_l + gyro_x_h
+ break;
+ case 5:
+ SpiReadIt(hspix, 0x00); // gyro_x_l + gyro_y_h
+ break;
+ case 6:
+ SpiReadIt(hspix, 0x00); // gyro_y_l + gyro_z_h
+ break;
+ case 7:
+ SpiReadIt(hspix, 0x00); // gyro_z_l + UNUSED
+ break;
+ }
+
+ *res = SPI_READY;
+ break;
+ }
+}
+
+static void SpiMurata(DataRawInt16 *data, SPI_HandleTypeDef *hspix, SpiOut *res,
+ SpiIn call) {
+ switch (call) {
+ case SPI_INIT:
+ InitMurata();
+ break;
+ case SPI_ZERO:
+ memset(data, 0, IMU_SAMPLES_PER_MS * sizeof(*data));
+ break;
+ case SPI_START:
+ data[timer_index].state = (hspix == &hspi3) ? 4 : 0;
+ data[timer_index].index = 0;
+ *res = SPI_READY;
+ break;
+
+ case SPI_RUN:
+ *res = SPI_BUSY;
+
+ SpiCsStart(hspix);
+
+ switch (data[timer_index].state) {
+ case 0:
+ SpiReadIt(hspix, READ_ACC_X);
+ break;
+ case 1:
+ SpiReadIt(hspix, READ_ACC_Y);
+ break;
+ case 2:
+ SpiReadIt(hspix, READ_ACC_Z);
+ break;
+ case 3:
+ SpiReadIt(hspix, READ_GYRO_X);
+ break;
+ case 4:
+ SpiReadIt(hspix, READ_TEMP);
+ break;
+ case 5:
+ SpiReadIt(hspix, READ_GYRO_Y);
+ break;
+ case 6:
+ SpiReadIt(hspix, READ_GYRO_Z);
+ break;
+ }
+
+ *res = SPI_READY;
+ break;
+ }
+}
+
+void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
+ if (htim == &htim1) {
+ timer_index++;
+ timer_index %= IMU_SAMPLES_PER_MS;
+
+ if (timer_index == 0) {
+ can_tx_packet_counter = 0;
+ AverageData();
+ ComposeData();
+ RealignData();
+
+ ConstructCanfdPacket(can_tx, &data_murata, &data_tdk);
+ can_out.can_counter++;
+ can_out.can_counter =
+ (can_out.can_counter == 0xFFFF) ? 0 : can_out.can_counter;
+
+ PWMSend(&htim3, TIM_CHANNEL_3, (data_murata.gyro_z));
+ PWMSend(&htim3, TIM_CHANNEL_4, (data_murata.gyro_z));
+
+ SpiTdk(tdk_data, &hspi1, &tdk_state, SPI_ZERO);
+ SpiMurata(uno_data, &hspi2, &uno_state, SPI_ZERO);
+ SpiMurata(due_data, &hspi3, &due_state, SPI_ZERO);
+ }
+
+ SpiTdk(tdk_data, &hspi1, &tdk_state, SPI_START);
+ SpiMurata(uno_data, &hspi2, &uno_state, SPI_START);
+ SpiMurata(due_data, &hspi3, &due_state, SPI_START);
+
+ if (tdk_state == SPI_READY && uno_state == SPI_READY &&
+ due_state == SPI_READY) {
+ for (int j = 0; j < 3; j++) {
+ tx_header.Identifier = can_tx_packet_counter + j + 1;
+ if (tx_header.Identifier == 9) {
+ break;
+ }
+ while (HAL_FDCAN_AddMessageToTxFifoQ(
+ &hfdcan2, &tx_header,
+ can_tx + (can_tx_packet_counter + j) * 8) != HAL_OK) {
+ // Error Handler will stop execution
+ }
+ }
+ can_tx_packet_counter += 3;
+
+ SpiTdk(tdk_data, &hspi1, &tdk_state, SPI_RUN);
+ SpiMurata(uno_data, &hspi2, &uno_state, SPI_RUN);
+ SpiMurata(due_data, &hspi3, &due_state, SPI_RUN);
+ }
+ }
+}
+
+void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
+ if (hspi == &hspi1) {
+ switch (tdk_data[timer_index].state) {
+ case 0:
+ tdk_data[timer_index].acc_x = (int16_t)(spi1_rx[0] << 8);
+ break;
+ case 1:
+ tdk_data[timer_index].acc_x |= (int16_t)spi1_rx[1];
+ tdk_data[timer_index].acc_y = (int16_t)(spi1_rx[0] << 8);
+ break;
+ case 2:
+ tdk_data[timer_index].acc_y |= (int16_t)spi1_rx[1];
+ tdk_data[timer_index].acc_z = (int16_t)(spi1_rx[0] << 8);
+ break;
+ case 3:
+ tdk_data[timer_index].acc_z |= (int16_t)spi1_rx[1];
+ tdk_data[timer_index].temp = (int16_t)(spi1_rx[0] << 8);
+ break;
+ case 4:
+ tdk_data[timer_index].temp |= (int16_t)spi1_rx[1];
+ tdk_data[timer_index].gyro_x = (int16_t)(spi1_rx[0] << 8);
+ break;
+ case 5:
+ tdk_data[timer_index].gyro_x |= (int16_t)spi1_rx[1];
+ tdk_data[timer_index].gyro_y = (int16_t)(spi1_rx[0] << 8);
+ break;
+ case 6:
+ tdk_data[timer_index].gyro_y |= (int16_t)spi1_rx[1];
+ tdk_data[timer_index].gyro_z = (int16_t)(spi1_rx[0] << 8);
+ break;
+ case 7:
+ tdk_data[timer_index].gyro_z |= (int16_t)spi1_rx[1];
+ break;
+ default:
+ SpiCsEnd(hspi);
+ return;
+ }
+
+ tdk_data[timer_index].state++;
+ if (tdk_data[timer_index].state == 8) {
+ SpiCsEnd(hspi);
+ tdk_data[timer_index].state = 0;
+ can_out.tdk_counter++;
+ can_out.tdk_counter =
+ (can_out.tdk_counter == 0xFFFF) ? 0 : can_out.tdk_counter;
+ return;
+ }
+
+ SpiTdk(tdk_data, hspi, &tdk_state, SPI_RUN);
+ return;
+
+ } else if (hspi == &hspi2 || hspi == &hspi3) {
+ SpiCsEnd(hspi);
+ ConvertEndianMurata(spi_murata_rx.byte, (hspi == &hspi2)
+ ? spi2_rx.four_bytes
+ : spi3_rx.four_bytes);
+
+ if (hspi == &hspi2) {
+ switch (uno_data[timer_index].state) {
+ case 0:
+ uno_data[timer_index].temp =
+ GET_SPI_DATA_INT16(spi_murata_rx.four_bytes);
+ break;
+ case 1:
+ uno_data[timer_index].acc_x =
+ GET_SPI_DATA_INT16(spi_murata_rx.four_bytes);
+ break;
+ case 2:
+ uno_data[timer_index].acc_y =
+ GET_SPI_DATA_INT16(spi_murata_rx.four_bytes);
+ break;
+ case 3:
+ uno_data[timer_index].acc_z =
+ GET_SPI_DATA_INT16(spi_murata_rx.four_bytes);
+ break;
+ case 4:
+ uno_data[timer_index].gyro_x =
+ GET_SPI_DATA_INT16(spi_murata_rx.four_bytes);
+ break;
+ default:
+ return;
+ }
+
+ if (uno_data[timer_index].index == 1) {
+ uno_data[timer_index].index = 0;
+
+ can_out.uno_counter++;
+ can_out.uno_counter =
+ (can_out.uno_counter == 0xFFFF) ? 0 : can_out.uno_counter;
+
+ return;
+ }
+
+ uno_data[timer_index].state++;
+
+ if (uno_data[timer_index].state == 5) {
+ uno_data[timer_index].state = 0;
+ uno_data[timer_index].index++;
+ }
+
+ SpiMurata(uno_data, hspi, &uno_state, SPI_RUN);
+
+ return;
+ } else if (hspi == &hspi3) {
+ switch (due_data[timer_index].state - 4) {
+ case 0:
+ due_data[timer_index].gyro_z =
+ GET_SPI_DATA_INT16(spi_murata_rx.four_bytes);
+ break;
+ case 1:
+ due_data[timer_index].temp =
+ GET_SPI_DATA_INT16(spi_murata_rx.four_bytes);
+ break;
+ case 2:
+ due_data[timer_index].gyro_y =
+ GET_SPI_DATA_INT16(spi_murata_rx.four_bytes);
+ break;
+ default:
+ return;
+ }
+
+ if (due_data[timer_index].index == 1) {
+ due_data[timer_index].index = 0;
+
+ can_out.due_counter++;
+ can_out.due_counter =
+ (can_out.due_counter == 0xFFFF) ? 0 : can_out.due_counter;
+
+ return;
+ }
+
+ due_data[timer_index].state++;
+
+ if (due_data[timer_index].state == 7) {
+ due_data[timer_index].state = 4;
+ due_data[timer_index].index++;
+ }
+
+ SpiMurata(due_data, hspi, &due_state, SPI_RUN);
+
+ return;
+ }
}
}
diff --git a/frc971/imu_fdcan/Dual_IMU/Core/Src/stm32g4xx_hal_msp.c b/frc971/imu_fdcan/Dual_IMU/Core/Src/stm32g4xx_hal_msp.c
index b4a4229..f315dfa 100644
--- a/frc971/imu_fdcan/Dual_IMU/Core/Src/stm32g4xx_hal_msp.c
+++ b/frc971/imu_fdcan/Dual_IMU/Core/Src/stm32g4xx_hal_msp.c
@@ -256,6 +256,9 @@
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+ /* SPI1 interrupt Init */
+ HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(SPI1_IRQn);
/* USER CODE BEGIN SPI1_MspInit 1 */
/* USER CODE END SPI1_MspInit 1 */
@@ -279,6 +282,9 @@
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+ /* SPI2 interrupt Init */
+ HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(SPI2_IRQn);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
@@ -302,6 +308,9 @@
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+ /* SPI3 interrupt Init */
+ HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(SPI3_IRQn);
/* USER CODE BEGIN SPI3_MspInit 1 */
/* USER CODE END SPI3_MspInit 1 */
@@ -329,6 +338,8 @@
*/
HAL_GPIO_DeInit(GPIOA, SCK_TDK_ST_Pin | MISO_TDK_Pin | MOSI_TDK_ST_Pin);
+ /* SPI1 interrupt DeInit */
+ HAL_NVIC_DisableIRQ(SPI1_IRQn);
/* USER CODE BEGIN SPI1_MspDeInit 1 */
/* USER CODE END SPI1_MspDeInit 1 */
@@ -346,6 +357,8 @@
*/
HAL_GPIO_DeInit(GPIOB, SCK_UNO_Pin | MISO_UNO_Pin | MOSI_UNO_Pin);
+ /* SPI2 interrupt DeInit */
+ HAL_NVIC_DisableIRQ(SPI2_IRQn);
/* USER CODE BEGIN SPI2_MspDeInit 1 */
/* USER CODE END SPI2_MspDeInit 1 */
@@ -363,6 +376,8 @@
*/
HAL_GPIO_DeInit(GPIOC, SCK_DUE_Pin | MISO_DUE_Pin | MOSI_DUE_Pin);
+ /* SPI3 interrupt DeInit */
+ HAL_NVIC_DisableIRQ(SPI3_IRQn);
/* USER CODE BEGIN SPI3_MspDeInit 1 */
/* USER CODE END SPI3_MspDeInit 1 */
@@ -376,7 +391,28 @@
* @retval None
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim_base) {
- if (htim_base->Instance == TIM3) {
+ if (htim_base->Instance == TIM1) {
+ /* USER CODE BEGIN TIM1_MspInit 0 */
+
+ /* USER CODE END TIM1_MspInit 0 */
+ /* Peripheral clock enable */
+ __HAL_RCC_TIM1_CLK_ENABLE();
+ /* TIM1 interrupt Init */
+ HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
+ /* USER CODE BEGIN TIM1_MspInit 1 */
+
+ /* USER CODE END TIM1_MspInit 1 */
+ } else if (htim_base->Instance == TIM2) {
+ /* USER CODE BEGIN TIM2_MspInit 0 */
+
+ /* USER CODE END TIM2_MspInit 0 */
+ /* Peripheral clock enable */
+ __HAL_RCC_TIM2_CLK_ENABLE();
+ /* USER CODE BEGIN TIM2_MspInit 1 */
+
+ /* USER CODE END TIM2_MspInit 1 */
+ } else if (htim_base->Instance == TIM3) {
/* USER CODE BEGIN TIM3_MspInit 0 */
/* USER CODE END TIM3_MspInit 0 */
@@ -400,7 +436,7 @@
PB0 ------> TIM3_CH3
PB1 ------> TIM3_CH4
*/
- GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
+ GPIO_InitStruct.Pin = PWM_RATE_Pin | PWM_HEADING_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
@@ -419,7 +455,28 @@
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim_base) {
- if (htim_base->Instance == TIM3) {
+ if (htim_base->Instance == TIM1) {
+ /* USER CODE BEGIN TIM1_MspDeInit 0 */
+
+ /* USER CODE END TIM1_MspDeInit 0 */
+ /* Peripheral clock disable */
+ __HAL_RCC_TIM1_CLK_DISABLE();
+
+ /* TIM1 interrupt DeInit */
+ HAL_NVIC_DisableIRQ(TIM1_UP_TIM16_IRQn);
+ /* USER CODE BEGIN TIM1_MspDeInit 1 */
+
+ /* USER CODE END TIM1_MspDeInit 1 */
+ } else if (htim_base->Instance == TIM2) {
+ /* USER CODE BEGIN TIM2_MspDeInit 0 */
+
+ /* USER CODE END TIM2_MspDeInit 0 */
+ /* Peripheral clock disable */
+ __HAL_RCC_TIM2_CLK_DISABLE();
+ /* USER CODE BEGIN TIM2_MspDeInit 1 */
+
+ /* USER CODE END TIM2_MspDeInit 1 */
+ } else if (htim_base->Instance == TIM3) {
/* USER CODE BEGIN TIM3_MspDeInit 0 */
/* USER CODE END TIM3_MspDeInit 0 */
diff --git a/frc971/imu_fdcan/Dual_IMU/Core/Src/stm32g4xx_it.c b/frc971/imu_fdcan/Dual_IMU/Core/Src/stm32g4xx_it.c
index a160264..f320906 100644
--- a/frc971/imu_fdcan/Dual_IMU/Core/Src/stm32g4xx_it.c
+++ b/frc971/imu_fdcan/Dual_IMU/Core/Src/stm32g4xx_it.c
@@ -56,7 +56,10 @@
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
-
+extern SPI_HandleTypeDef hspi1;
+extern SPI_HandleTypeDef hspi2;
+extern SPI_HandleTypeDef hspi3;
+extern TIM_HandleTypeDef htim1;
/* USER CODE BEGIN EV */
/* USER CODE END EV */
@@ -185,6 +188,59 @@
/* please refer to the startup file (startup_stm32g4xx.s). */
/******************************************************************************/
+/**
+ * @brief This function handles TIM1 update interrupt and TIM16 global
+ * interrupt.
+ */
+void TIM1_UP_TIM16_IRQHandler(void) {
+ /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 0 */
+
+ /* USER CODE END TIM1_UP_TIM16_IRQn 0 */
+ HAL_TIM_IRQHandler(&htim1);
+ /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 1 */
+
+ /* USER CODE END TIM1_UP_TIM16_IRQn 1 */
+}
+
+/**
+ * @brief This function handles SPI1 global interrupt.
+ */
+void SPI1_IRQHandler(void) {
+ /* USER CODE BEGIN SPI1_IRQn 0 */
+
+ /* USER CODE END SPI1_IRQn 0 */
+ HAL_SPI_IRQHandler(&hspi1);
+ /* USER CODE BEGIN SPI1_IRQn 1 */
+
+ /* USER CODE END SPI1_IRQn 1 */
+}
+
+/**
+ * @brief This function handles SPI2 global interrupt.
+ */
+void SPI2_IRQHandler(void) {
+ /* USER CODE BEGIN SPI2_IRQn 0 */
+
+ /* USER CODE END SPI2_IRQn 0 */
+ HAL_SPI_IRQHandler(&hspi2);
+ /* USER CODE BEGIN SPI2_IRQn 1 */
+
+ /* USER CODE END SPI2_IRQn 1 */
+}
+
+/**
+ * @brief This function handles SPI3 global interrupt.
+ */
+void SPI3_IRQHandler(void) {
+ /* USER CODE BEGIN SPI3_IRQn 0 */
+
+ /* USER CODE END SPI3_IRQn 0 */
+ HAL_SPI_IRQHandler(&hspi3);
+ /* USER CODE BEGIN SPI3_IRQn 1 */
+
+ /* USER CODE END SPI3_IRQn 1 */
+}
+
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
diff --git a/frc971/imu_fdcan/Dual_IMU/Dual_IMU.ioc b/frc971/imu_fdcan/Dual_IMU/Dual_IMU.ioc
index dd4a2c8..ffc0648 100644
--- a/frc971/imu_fdcan/Dual_IMU/Dual_IMU.ioc
+++ b/frc971/imu_fdcan/Dual_IMU/Dual_IMU.ioc
@@ -28,16 +28,18 @@
Mcu.Family=STM32G4
Mcu.IP0=ADC5
Mcu.IP1=FDCAN2
-Mcu.IP10=USB
+Mcu.IP10=TIM3
+Mcu.IP11=USART1
+Mcu.IP12=USB
Mcu.IP2=NVIC
Mcu.IP3=RCC
Mcu.IP4=SPI1
Mcu.IP5=SPI2
Mcu.IP6=SPI3
Mcu.IP7=SYS
-Mcu.IP8=TIM3
-Mcu.IP9=USART1
-Mcu.IPNb=11
+Mcu.IP8=TIM1
+Mcu.IP9=TIM2
+Mcu.IPNb=13
Mcu.Name=STM32G473R(B-C-E)Tx
Mcu.Package=LQFP64
Mcu.Pin0=PC13
@@ -89,12 +91,14 @@
Mcu.Pin50=PB9
Mcu.Pin51=VP_SYS_VS_Systick
Mcu.Pin52=VP_SYS_VS_DBSignals
-Mcu.Pin53=VP_TIM3_VS_ClockSourceINT
+Mcu.Pin53=VP_TIM1_VS_ClockSourceINT
+Mcu.Pin54=VP_TIM2_VS_ClockSourceINT
+Mcu.Pin55=VP_TIM3_VS_ClockSourceINT
Mcu.Pin6=PC1
Mcu.Pin7=PC2
Mcu.Pin8=PC3
Mcu.Pin9=PA0
-Mcu.PinsNb=54
+Mcu.PinsNb=56
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32G473RETx
@@ -108,8 +112,12 @@
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SPI1_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
+NVIC.SPI2_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
+NVIC.SPI3_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
+NVIC.TIM1_UP_TIM16_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
PA0.GPIOParameters=GPIO_Label
PA0.GPIO_Label=INT_TDK
@@ -176,8 +184,12 @@
PA8.Signal=ADC5_IN1
PA9.Locked=true
PA9.Signal=GPIO_Output
+PB0.GPIOParameters=GPIO_Label
+PB0.GPIO_Label=PWM_RATE
PB0.Locked=true
PB0.Signal=S_TIM3_CH3
+PB1.GPIOParameters=GPIO_Label
+PB1.GPIO_Label=PWM_HEADING
PB1.Locked=true
PB1.Signal=S_TIM3_CH4
PB10.Locked=true
@@ -326,7 +338,7 @@
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=
ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_FDCAN2_Init-FDCAN2-false-HAL-true,4-MX_ADC5_Init-ADC5-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI2_Init-SPI2-false-HAL-true,7-MX_SPI3_Init-SPI3-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_TIM3_Init-TIM3-false-HAL-true,10-MX_USB_PCD_Init-USB-false-HAL-true
+ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_FDCAN2_Init-FDCAN2-false-HAL-true,4-MX_ADC5_Init-ADC5-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI2_Init-SPI2-false-HAL-true,7-MX_SPI3_Init-SPI3-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_TIM3_Init-TIM3-false-HAL-true,10-MX_USB_PCD_Init-USB-false-HAL-true,11-MX_TIM2_Init-TIM2-false-HAL-true,12-MX_TIM1_Init-TIM1-false-HAL-true
RCC.ADC12Freq_Value=168000000
RCC.ADC345Freq_Value=168000000
RCC.AHBFreq_Value=168000000
@@ -409,16 +421,31 @@
SPI3.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,DataSize,CLKPhase,CLKPolarity
SPI3.Mode=SPI_MODE_MASTER
SPI3.VirtualType=VM_MASTER
+TIM1.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
+TIM1.IPParameters=Prescaler,PeriodNoDither,AutoReloadPreload
+TIM1.PeriodNoDither=333
+TIM1.Prescaler=168-1
+TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
+TIM2.IPParameters=Prescaler,AutoReloadPreload,PeriodNoDither
+TIM2.PeriodNoDither=4294967295
+TIM2.Prescaler=168-1
TIM3.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
TIM3.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
-TIM3.IPParameters=Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,Prescaler
-TIM3.Prescaler=2563
+TIM3.IPParameters=Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,Prescaler,PeriodNoDither
+TIM3.PeriodNoDither=35000
+TIM3.Prescaler=24-1
USART1.IPParameters=VirtualMode-Asynchronous
USART1.VirtualMode-Asynchronous=VM_ASYNC
+USB.IPParameters=Sof_enable
+USB.Sof_enable=DISABLE
VP_SYS_VS_DBSignals.Mode=DisableDeadBatterySignals
VP_SYS_VS_DBSignals.Signal=SYS_VS_DBSignals
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
+VP_TIM1_VS_ClockSourceINT.Mode=Internal
+VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
+VP_TIM2_VS_ClockSourceINT.Mode=Internal
+VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT
VP_TIM3_VS_ClockSourceINT.Mode=Internal
VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT
VREF+.Locked=true