firmware defines
This commit is contained in:
44
firmware/boards/genericSTM32G431CB.json
Normal file
44
firmware/boards/genericSTM32G431CB.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"build": {
|
||||
"core": "stm32",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DSTM32G4xx -DSTM32G431xx",
|
||||
"f_cpu": "170000000L",
|
||||
"mcu": "stm32g431cbu6",
|
||||
"product_line": "STM32G431xx",
|
||||
"variant": "STM32G4xx/G431C(6-8-B)U_G441CBU"
|
||||
},
|
||||
"connectivity": [
|
||||
"can"
|
||||
],
|
||||
"debug": {
|
||||
"default_tools": [
|
||||
"stlink"
|
||||
],
|
||||
"jlink_device": "STM32G431CB",
|
||||
"openocd_target": "stm32g4x",
|
||||
"svd_path": "STM32G431xx.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"cmsis",
|
||||
"libopencm3",
|
||||
"stm32cube",
|
||||
"zephyr"
|
||||
],
|
||||
"name": "STM32G431CB",
|
||||
"upload": {
|
||||
"maximum_ram_size": 32768,
|
||||
"maximum_size": 131072,
|
||||
"protocol": "stlink",
|
||||
"protocols": [
|
||||
"stlink",
|
||||
"jlink",
|
||||
"cmsis-dap",
|
||||
"blackmagic",
|
||||
"mbed"
|
||||
]
|
||||
},
|
||||
"url": "https://www.st.com/en/microcontrollers-microprocessors/stm32g431cb.html",
|
||||
"vendor": "ST"
|
||||
}
|
||||
39
firmware/include/README
Normal file
39
firmware/include/README
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
38
firmware/include/lemon-pepper.h
Normal file
38
firmware/include/lemon-pepper.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
// MOTOR DRIVER L6226Q
|
||||
#define U_PWM PA10
|
||||
#define V_PWM PA9
|
||||
#define W_PWM PA1
|
||||
|
||||
#define A1 PA0
|
||||
#define A2 PA1
|
||||
#define B1 PA9
|
||||
#define B2 PA10
|
||||
|
||||
#define MOT_EN PB12
|
||||
|
||||
// ENCODER MT6835
|
||||
#define ENC_A PB4
|
||||
#define ENC_B PB5
|
||||
#define ENC_Z PB3
|
||||
|
||||
#define ENC_COPI PA7
|
||||
#define ENC_CIPO PA6
|
||||
#define ENC_SCK PA5
|
||||
#define ENC_CS PC4
|
||||
#define ENC_CAL PA4
|
||||
|
||||
// CURRENT SENSE
|
||||
#define ISENSE_U PA3
|
||||
#define ISENSE_V PB13
|
||||
#define ISENSE_W PB0
|
||||
|
||||
// COMMUNICATION
|
||||
#define CAN_TX PB8
|
||||
#define CAN_RX PB9
|
||||
|
||||
// AUX
|
||||
#define LED_GOOD PB10
|
||||
#define LED_FAULT PB11
|
||||
|
||||
185
firmware/ldscript.ld
Normal file
185
firmware/ldscript.ld
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
**
|
||||
** @file : LinkerScript.ld
|
||||
**
|
||||
** @author : Auto-generated by STM32CubeIDE
|
||||
**
|
||||
** @brief : Linker script for STM32G431CBUx Device from STM32G4 series
|
||||
** 128Kbytes FLASH
|
||||
** 32Kbytes RAM
|
||||
**
|
||||
** Set heap size, stack size and stack location according
|
||||
** to application requirements.
|
||||
**
|
||||
** Set memory bank area and size if external memory is used
|
||||
**
|
||||
** Target : STMicroelectronics STM32
|
||||
**
|
||||
** Distribution: The file is distributed as is, without any warranty
|
||||
** of any kind.
|
||||
**
|
||||
******************************************************************************
|
||||
** @attention
|
||||
**
|
||||
** Copyright (c) 2023 STMicroelectronics.
|
||||
** All rights reserved.
|
||||
**
|
||||
** This software is licensed under terms that can be found in the LICENSE file
|
||||
** in the root directory of this software component.
|
||||
** If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
**
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Entry Point */
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
/* Highest address of the user mode stack */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
|
||||
|
||||
_Min_Heap_Size = 0x200; /* required amount of heap */
|
||||
_Min_Stack_Size = 0x400; /* required amount of stack */
|
||||
|
||||
/* Memories definition */
|
||||
MEMORY
|
||||
{
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
|
||||
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
|
||||
}
|
||||
|
||||
/* Sections */
|
||||
SECTIONS
|
||||
{
|
||||
/* The startup code into "FLASH" Rom type memory */
|
||||
.isr_vector :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.isr_vector)) /* Startup code */
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
/* The program code and other data into "FLASH" Rom type memory */
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.glue_7) /* glue arm to thumb code */
|
||||
*(.glue_7t) /* glue thumb to arm code */
|
||||
*(.eh_frame)
|
||||
|
||||
KEEP (*(.init))
|
||||
KEEP (*(.fini))
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .; /* define a global symbols at end of code */
|
||||
} >FLASH
|
||||
|
||||
/* Constant data into "FLASH" Rom type memory */
|
||||
.rodata :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.ARM.extab : {
|
||||
. = ALIGN(4);
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.ARM : {
|
||||
. = ALIGN(4);
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
__exidx_end = .;
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.preinit_array :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array*))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.init_array :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array*))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.fini_array :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
KEEP (*(.fini_array*))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
/* Used by the startup to initialize data */
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
/* Initialized data sections into "RAM" Ram type memory */
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .; /* create a global symbol at data start */
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
*(.RamFunc) /* .RamFunc sections */
|
||||
*(.RamFunc*) /* .RamFunc* sections */
|
||||
|
||||
. = ALIGN(4);
|
||||
_edata = .; /* define a global symbol at data end */
|
||||
|
||||
} >RAM AT> FLASH
|
||||
|
||||
/* Uninitialized data section into "RAM" Ram type memory */
|
||||
. = ALIGN(4);
|
||||
.bss :
|
||||
{
|
||||
/* This is used by the startup in order to initialize the .bss section */
|
||||
_sbss = .; /* define a global symbol at bss start */
|
||||
__bss_start__ = _sbss;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
_ebss = .; /* define a global symbol at bss end */
|
||||
__bss_end__ = _ebss;
|
||||
} >RAM
|
||||
|
||||
/* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
|
||||
._user_heap_stack :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
PROVIDE ( end = . );
|
||||
PROVIDE ( _end = . );
|
||||
. = . + _Min_Heap_Size;
|
||||
. = . + _Min_Stack_Size;
|
||||
. = ALIGN(8);
|
||||
} >RAM
|
||||
|
||||
/* Remove information from the compiler libraries */
|
||||
/DISCARD/ :
|
||||
{
|
||||
libc.a ( * )
|
||||
libm.a ( * )
|
||||
libgcc.a ( * )
|
||||
}
|
||||
|
||||
.ARM.attributes 0 : { *(.ARM.attributes) }
|
||||
}
|
||||
46
firmware/lib/README
Normal file
46
firmware/lib/README
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
263
firmware/lib/can/can.cpp
Normal file
263
firmware/lib/can/can.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
#include "can.h"
|
||||
|
||||
enum canAction
|
||||
{
|
||||
WaitForCmd,
|
||||
TxDeviceInfo,
|
||||
SearchForID
|
||||
};
|
||||
|
||||
FDCAN_HandleTypeDef hfdcan1;
|
||||
FDCAN_FilterTypeDef sFilterConfig;
|
||||
FDCAN_RxHeaderTypeDef RxHeader;
|
||||
FDCAN_TxHeaderTypeDef TxHeader;
|
||||
|
||||
canAction FDCAN_State = WaitForCmd;
|
||||
const uint16_t FDCAN_GlobalID = 0x7CC;
|
||||
uint16_t FDCAN_TempID;
|
||||
uint8_t foundExtDevice = 0;
|
||||
uint8_t JunkBuf[8];
|
||||
uint8_t TxData[8];
|
||||
uint8_t RxData[8];
|
||||
|
||||
extern "C" void FDCAN1_IT0_IRQHandler(void);
|
||||
|
||||
void FDCAN_Error_Handler(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
void FDCAN_Init(void)
|
||||
{
|
||||
hfdcan1.Instance = FDCAN1;
|
||||
hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
|
||||
hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_NO_BRS;
|
||||
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
|
||||
hfdcan1.Init.AutoRetransmission = ENABLE;
|
||||
hfdcan1.Init.TransmitPause = DISABLE;
|
||||
hfdcan1.Init.ProtocolException = DISABLE;
|
||||
|
||||
// transceiver and peripheral clock specific values
|
||||
hfdcan1.Init.NominalPrescaler = 1;
|
||||
hfdcan1.Init.NominalSyncJumpWidth = 2;
|
||||
hfdcan1.Init.NominalTimeSeg1 = 21;
|
||||
hfdcan1.Init.NominalTimeSeg2 = 2;
|
||||
|
||||
hfdcan1.Init.DataPrescaler = 1;
|
||||
hfdcan1.Init.DataSyncJumpWidth = 5;
|
||||
hfdcan1.Init.DataTimeSeg1 = 6;
|
||||
hfdcan1.Init.DataTimeSeg2 = 5;
|
||||
//
|
||||
|
||||
hfdcan1.Init.StdFiltersNbr = 1;
|
||||
hfdcan1.Init.ExtFiltersNbr = 0;
|
||||
hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
|
||||
|
||||
if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
|
||||
{
|
||||
FDCAN_Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
void FDCAN_ConfigFilter(uint16_t canID)
|
||||
{
|
||||
sFilterConfig.IdType = FDCAN_STANDARD_ID;
|
||||
sFilterConfig.FilterIndex = 0;
|
||||
sFilterConfig.FilterType = FDCAN_FILTER_DUAL;
|
||||
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
|
||||
sFilterConfig.FilterID1 = canID;
|
||||
sFilterConfig.FilterID2 = FDCAN_GlobalID;
|
||||
if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
|
||||
{
|
||||
/* Filter configuration Error */
|
||||
FDCAN_Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
void FDCAN_ConfigTxHeader(uint16_t canID)
|
||||
{
|
||||
TxHeader.Identifier = canID;
|
||||
TxHeader.IdType = FDCAN_STANDARD_ID;
|
||||
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
|
||||
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
|
||||
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
|
||||
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
|
||||
TxHeader.FDFormat = FDCAN_FD_CAN;
|
||||
TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
|
||||
TxHeader.MessageMarker = 0;
|
||||
}
|
||||
|
||||
void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef *hfdcan)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
|
||||
if (hfdcan->Instance == FDCAN1)
|
||||
{
|
||||
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
|
||||
PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_HSE;
|
||||
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
__HAL_RCC_FDCAN_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
|
||||
/**FDCAN1 GPIO Configuration
|
||||
PB8-BOOT0 ------> FDCAN1_RX
|
||||
PB9 ------> FDCAN1_TX
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef *hfdcan)
|
||||
{
|
||||
|
||||
if (hfdcan->Instance == FDCAN1)
|
||||
{
|
||||
__HAL_RCC_FDCAN_CLK_DISABLE();
|
||||
|
||||
/**FDCAN1 GPIO Configuration
|
||||
PB8-BOOT0 ------> FDCAN1_RX
|
||||
PB9 ------> FDCAN1_TX
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8 | GPIO_PIN_9);
|
||||
|
||||
HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void FDCAN1_IT0_IRQHandler(void)
|
||||
{
|
||||
HAL_FDCAN_IRQHandler(&hfdcan1);
|
||||
}
|
||||
|
||||
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
|
||||
{
|
||||
if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET)
|
||||
{
|
||||
HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader, RxData);
|
||||
}
|
||||
|
||||
if (RxHeader.RxFrameType == FDCAN_REMOTE_FRAME)
|
||||
{
|
||||
// Reply globally but put the replying ID in the data packet.
|
||||
TxHeader.Identifier = FDCAN_GlobalID;
|
||||
memset(TxData, 0x00, 8 * sizeof(uint8_t));
|
||||
memcpy(&TxData, (sFilterConfig.FilterID1), sizeof(uint16_t));
|
||||
FDCAN_SendMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (FDCAN_State)
|
||||
{
|
||||
case WaitForCmd:
|
||||
// Set some flag to indicate that sfoc has a new command.
|
||||
if (RxHeader.Identifier = FDCAN_GlobalID)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case SearchForID:
|
||||
foundExtDevice = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FDCAN_SendMessage(void)
|
||||
{
|
||||
switch (FDCAN_State)
|
||||
{
|
||||
case TxDeviceInfo:
|
||||
break;
|
||||
|
||||
case SearchForID:
|
||||
TxHeader.Identifier = FDCAN_TempID;
|
||||
TxHeader.TxFrameType = FDCAN_REMOTE_FRAME;
|
||||
TxHeader.DataLength = FDCAN_DLC_BYTES_0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData) != HAL_OK)
|
||||
{
|
||||
FDCAN_Error_Handler();
|
||||
}
|
||||
|
||||
// Set the tx parameters back to normal.
|
||||
TxHeader.Identifier = sFilterConfig.FilterID1;
|
||||
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
|
||||
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
|
||||
}
|
||||
|
||||
uint16_t FDCAN_FindUniqueID(void)
|
||||
{
|
||||
FDCAN_TempID = 0x000;
|
||||
FDCAN_State = SearchForID;
|
||||
|
||||
while (1)
|
||||
{
|
||||
foundExtDevice = 0;
|
||||
FDCAN_SendMessage();
|
||||
delay(100);
|
||||
if (foundExtDevice)
|
||||
{
|
||||
// Try the next address.
|
||||
FDCAN_TempID++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We found a unique device ID!
|
||||
FDCAN_State = WaitForCmd;
|
||||
FDCAN_ChangeID(FDCAN_TempID);
|
||||
digitalWrite(PA7, HIGH);
|
||||
return FDCAN_TempID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FDCAN_ChangeID(uint16_t newID)
|
||||
{
|
||||
// HAL_FDCAN_Stop();
|
||||
FDCAN_ConfigFilter(newID);
|
||||
FDCAN_ConfigTxHeader(newID);
|
||||
// HAL_FDCAN_Start();
|
||||
}
|
||||
|
||||
void FDCAN_Start(uint16_t canID)
|
||||
{
|
||||
FDCAN_Init();
|
||||
FDCAN_ConfigFilter(canID);
|
||||
FDCAN_ConfigTxHeader(canID);
|
||||
|
||||
if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
|
||||
{
|
||||
FDCAN_Error_Handler();
|
||||
}
|
||||
|
||||
if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
|
||||
{
|
||||
FDCAN_Error_Handler();
|
||||
}
|
||||
}
|
||||
17
firmware/lib/can/can.h
Normal file
17
firmware/lib/can/can.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* CAN header
|
||||
*/
|
||||
|
||||
#ifndef AIOLI_CAN_H
|
||||
#define AIOLI_CAN_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "stm32g4xx_hal.h"
|
||||
#include "stm32g4xx_hal_fdcan.h"
|
||||
|
||||
void FDCAN_Start(uint16_t canID);
|
||||
void FDCAN_SendMessage();
|
||||
void FDCAN_ChangeID(uint16_t newID);
|
||||
uint16_t FDCAN_FindUniqueID(void);
|
||||
|
||||
#endif
|
||||
26
firmware/lib/dfu/dfu.cpp
Normal file
26
firmware/lib/dfu/dfu.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "stm32g4xx_hal.h"
|
||||
#include "stm32g4xx_hal_conf.h"
|
||||
#include "stm32g4xx_hal_rcc.h"
|
||||
|
||||
void perform_system_reset(void){
|
||||
__disable_irq();
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
// https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/
|
||||
void jump_to_bootloader(void){
|
||||
__enable_irq();
|
||||
HAL_RCC_DeInit();
|
||||
HAL_DeInit();
|
||||
SysTick->CTRL = SysTick->LOAD = SysTick->VAL = 0;
|
||||
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
|
||||
|
||||
const uint32_t p = (*((uint32_t *) 0x1FFF0000));
|
||||
__set_MSP( p );
|
||||
|
||||
void (*SysMemBootJump)(void);
|
||||
SysMemBootJump = (void (*)(void)) (*((uint32_t *) 0x1FFF0004));
|
||||
SysMemBootJump();
|
||||
|
||||
while( 1 ) {}
|
||||
}
|
||||
7
firmware/lib/dfu/dfu.h
Normal file
7
firmware/lib/dfu/dfu.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef BOOTLOADER_H
|
||||
#define BOOTLOADER_H
|
||||
|
||||
void perform_system_reset(void);
|
||||
void jump_to_bootloader(void);
|
||||
|
||||
#endif
|
||||
50
firmware/src/clock.c
Normal file
50
firmware/src/clock.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "pins_arduino.h"
|
||||
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
* @retval None
|
||||
*/
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
|
||||
/** Configure the main internal regulator output voltage
|
||||
*/
|
||||
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
|
||||
|
||||
/** Initializes the RCC Oscillators according to the specified parameters
|
||||
* in the RCC_OscInitTypeDef structure.
|
||||
*/
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI48
|
||||
|RCC_OSCILLATORTYPE_HSE;
|
||||
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
||||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||||
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
|
||||
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||||
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
|
||||
RCC_OscInitStruct.PLL.PLLN = 28;
|
||||
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
|
||||
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV8;
|
||||
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
|
||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/** Initializes the CPU, AHB and APB buses clocks
|
||||
*/
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
||||
|
||||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
163
firmware/src/main.cpp
Normal file
163
firmware/src/main.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include <SimpleFOC.h>
|
||||
#include <SimpleFOCDrivers.h>
|
||||
#include "encoders/MT6835/MagneticSensorMT6835.h"
|
||||
|
||||
#include "stm32g4xx_hal_conf.h"
|
||||
#include "stm32g4xx_hal_fdcan.h"
|
||||
|
||||
#include "can.h"
|
||||
#include "dfu.h"
|
||||
#include "lemon-pepper.h"
|
||||
|
||||
#define USBD_MANUFACTURER_STRING "matei repair lab"
|
||||
#define USBD_PRODUCT_STRING_FS "lemon-pepper-stepper"
|
||||
|
||||
// board specific data
|
||||
typedef struct
|
||||
{
|
||||
uint16_t signature;
|
||||
int8_t electricalDir;
|
||||
float electricalZero;
|
||||
uint8_t canID;
|
||||
}userData;
|
||||
|
||||
userData boardData;
|
||||
const uint16_t magicWord = 0xAF0C;
|
||||
|
||||
// canbus things
|
||||
extern uint8_t TxData[8];
|
||||
extern uint8_t RxData[8];
|
||||
|
||||
// simpleFOC things
|
||||
#define POLEPAIRS 7
|
||||
#define RPHASE 1.4
|
||||
#define MOTORKV 1000
|
||||
|
||||
SPISettings myMT6835SPISettings(1000000, MT6835_BITORDER, SPI_MODE3);
|
||||
MagneticSensorMT6835 sensor = MagneticSensorMT6835(ENC_CS, myMT6835SPISettings);
|
||||
|
||||
BLDCDriver3PWM driver = BLDCDriver3PWM(U_PWM, V_PWM, W_PWM, U_EN, V_EN, W_EN);
|
||||
BLDCMotor motor = BLDCMotor(POLEPAIRS, RPHASE, MOTORKV);
|
||||
MagneticSensorMT6701SSI enc = MagneticSensorMT6701SSI(ENC_CS);
|
||||
Commander commander = Commander(SerialUSB);
|
||||
|
||||
// Prototypes
|
||||
void configureFOC(void);
|
||||
void configureCAN(void);
|
||||
void userButton_IT(void);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// SCB->VTOR == 0x08000000;
|
||||
pinMode(USER_LED, OUTPUT);
|
||||
attachInterrupt(USER_BUTTON, userButton_IT, HIGH);
|
||||
|
||||
SerialUSB.begin(115200);
|
||||
|
||||
EEPROM.get(0, boardData);
|
||||
|
||||
configureCAN();
|
||||
configureFOC();
|
||||
|
||||
if(boardData.canID == 0x000)
|
||||
{
|
||||
// If the can ID is not initialized, then we'll look for a free ID.
|
||||
boardData.canID = FDCAN_FindUniqueID();
|
||||
SerialUSB.println(boardData.canID);
|
||||
}
|
||||
|
||||
if(boardData.signature != magicWord)
|
||||
{
|
||||
// If the EEPROM has not been initalized yet, save all the known data.
|
||||
EEPROM.put(0, boardData);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
motor.loopFOC();
|
||||
motor.move();
|
||||
commander.run();
|
||||
|
||||
#ifdef HAS_MONITOR
|
||||
motor.monitor();
|
||||
#endif
|
||||
}
|
||||
|
||||
void doMotor(char *cmd)
|
||||
{
|
||||
commander.motor(&motor, cmd);
|
||||
}
|
||||
|
||||
void configureFOC(void){
|
||||
commander.add('M', doMotor, "motor");
|
||||
commander.verbose = VerboseMode::machine_readable;
|
||||
|
||||
#ifdef SIMPLEFOC_STM32_DEBUG
|
||||
SimpleFOCDebug::enable(&SerialUSB);
|
||||
#endif
|
||||
|
||||
// Encoder initialization.
|
||||
// Encoder on SPI1
|
||||
enc.init();
|
||||
|
||||
// Driver initialization.
|
||||
driver.pwm_frequency = 32000;
|
||||
driver.voltage_power_supply = 5;
|
||||
driver.voltage_limit = 2.5;
|
||||
driver.init();
|
||||
|
||||
// Motor PID parameters.
|
||||
motor.PID_velocity.P = 0.2;
|
||||
motor.PID_velocity.I = 3;
|
||||
motor.PID_velocity.D = 0.002;
|
||||
motor.PID_velocity.output_ramp = 100;
|
||||
motor.LPF_velocity.Tf = 0.5;
|
||||
motor.LPF_angle.Tf = 0; // try to avoid
|
||||
|
||||
// Motor initialization.
|
||||
motor.voltage_sensor_align = 2;
|
||||
motor.current_limit = 0.5;
|
||||
motor.velocity_limit = 50;
|
||||
motor.controller = MotionControlType::velocity;
|
||||
motor.foc_modulation = FOCModulationType::SinePWM;
|
||||
|
||||
// Monitor initialization
|
||||
#ifdef HAS_MONITOR
|
||||
motor.useMonitoring(SerialUSB);
|
||||
motor.monitor_start_char = 'M';
|
||||
motor.monitor_end_char = 'M';
|
||||
motor.monitor_downsample = 250;
|
||||
#endif
|
||||
|
||||
motor.linkSensor(&enc);
|
||||
motor.linkDriver(&driver);
|
||||
|
||||
motor.target = 0;
|
||||
|
||||
if(boardData.signature != magicWord){
|
||||
// If we have not initialized the EEPROM before.
|
||||
motor.init();
|
||||
motor.initFOC();
|
||||
|
||||
boardData.signature = magicWord;
|
||||
boardData.electricalZero = motor.zero_electric_angle;
|
||||
boardData.electricalDir = motor.sensor_direction;
|
||||
}
|
||||
else{
|
||||
motor.zero_electric_angle = boardData.electricalZero;
|
||||
motor.sensor_direction = boardData.electricalDir;
|
||||
motor.init();
|
||||
motor.initFOC();
|
||||
}
|
||||
}
|
||||
|
||||
void configureCAN(void){
|
||||
FDCAN_Start(0x000);
|
||||
}
|
||||
|
||||
|
||||
11
firmware/test/README
Normal file
11
firmware/test/README
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||
Reference in New Issue
Block a user