Created
April 9, 2025 13:14
-
-
Save friesendrywall/b6d7e7af07f7e89eb851784bf3893c5d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern "C" { void DMA1_Channel5_IRQHandler(void); } | |
#include "MagneticSensorAS5048.h" | |
#include "stm32g4xx_ll_dma.h" | |
#include "stm32g4xx_ll_bus.h" | |
#define M1_ENCODER_CS_Pin LL_GPIO_PIN_8 | |
#define M1_ENCODER_CS_GPIO_Port GPIOB | |
#define M1_ENCODER_CLK_Pin LL_GPIO_PIN_7 | |
#define M1_ENCODER_CLK_GPIO_Port GPIOB | |
#define M1_ENCODER_MISO_Pin LL_GPIO_PIN_6 | |
#define M1_ENCODER_MISO_GPIO_Port GPIOB | |
volatile uint32_t position = 0; | |
volatile uint32_t direction = 0; | |
#define PINSET(x) (x) | |
#define PINCLR(x) (x << 16) | |
static uint32_t dmaData32[40] = { | |
PINSET(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 0 | |
PINSET(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 1 | |
PINSET(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 2 | |
PINSET(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 3 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 4 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 5 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 6 #1 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 7 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 8 #2 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 9 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 10 #3 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 11 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 12 #4 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 13 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 14 #5 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 15 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 16 #6 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 17 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 18 #7 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 19 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 20 #8 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 21 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 22 #9 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 23 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 24 #10 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 25 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 26 #11 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 27 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 28 #12 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 29 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 30 #13 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 31 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 32 #14 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 33 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 34 #15 | |
PINCLR(M1_ENCODER_CS_Pin) | PINSET(M1_ENCODER_CLK_Pin), // 35 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 36 #16 | |
PINCLR(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 37 | |
PINSET(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 38 | |
PINSET(M1_ENCODER_CS_Pin) | PINCLR(M1_ENCODER_CLK_Pin), // 39 | |
}; | |
static volatile uint16_t dmaInData[40] = {0}; | |
static void MX_GPIO_Init(void) { | |
LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | |
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); | |
GPIO_InitStruct.Pin = M1_ENCODER_CS_Pin | M1_ENCODER_CLK_Pin; | |
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT; | |
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; | |
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | |
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | |
LL_GPIO_Init(M1_ENCODER_CS_GPIO_Port, &GPIO_InitStruct); | |
GPIO_InitStruct.Pin = M1_ENCODER_MISO_Pin; | |
GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT; | |
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM; | |
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; | |
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; | |
LL_GPIO_Init(M1_ENCODER_MISO_GPIO_Port, &GPIO_InitStruct); | |
/* USER CODE END MX_GPIO_Init_2 */ | |
} | |
static void MX_TIM8_Init(void) { | |
LL_TIM_InitTypeDef TIM_InitStruct = {0}; | |
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM8); | |
TIM_InitStruct.Prescaler = 0; | |
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; | |
TIM_InitStruct.Autoreload = 65535; | |
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; | |
TIM_InitStruct.RepetitionCounter = 0; | |
LL_TIM_Init(TIM8, &TIM_InitStruct); | |
LL_TIM_DisableARRPreload(TIM8); | |
LL_TIM_SetClockSource(TIM8, LL_TIM_CLOCKSOURCE_INTERNAL); | |
// LL_TIM_SetTriggerOutput(TIM8, LL_TIM_TRGO_RESET); | |
// LL_TIM_SetTriggerOutput2(TIM8, LL_TIM_TRGO2_RESET); | |
LL_TIM_DisableMasterSlaveMode(TIM8); | |
LL_TIM_SetPrescaler(TIM8, 0); | |
LL_TIM_SetAutoReload(TIM8, SystemCoreClock / (1000000)); | |
LL_TIM_OC_SetMode(TIM8, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FROZEN); | |
LL_TIM_OC_SetCompareCH2(TIM8, (LL_TIM_GetAutoReload(TIM8) / 4)); | |
LL_TIM_CC_EnableChannel(TIM8, LL_TIM_CHANNEL_CH2); | |
LL_TIM_EnableCounter(TIM8); | |
/* TIM8 DMA TIM8_CH1 setup */ | |
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMAMUX_REQ_TIM8_CH2); | |
LL_DMA_ConfigTransfer( | |
DMA1, LL_DMA_CHANNEL_4, | |
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | | |
LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT | | |
LL_DMA_MDATAALIGN_WORD | LL_DMA_PDATAALIGN_WORD | | |
LL_DMA_PRIORITY_HIGH); | |
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_4, (uint32_t)dmaData32, | |
(uint32_t)&(M1_ENCODER_CS_GPIO_Port)->BSRR, | |
LL_DMA_DIRECTION_MEMORY_TO_PERIPH); | |
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_5, LL_DMAMUX_REQ_TIM8_CH2); | |
LL_DMA_ConfigTransfer(DMA1, LL_DMA_CHANNEL_5, | |
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | | |
LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | | |
LL_DMA_MEMORY_INCREMENT | | |
LL_DMA_PDATAALIGN_HALFWORD | | |
LL_DMA_MDATAALIGN_HALFWORD | LL_DMA_PRIORITY_HIGH); | |
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_5, | |
(uint32_t)&(M1_ENCODER_CS_GPIO_Port)->IDR, | |
(uint32_t)dmaInData, | |
LL_DMA_DIRECTION_PERIPH_TO_MEMORY); | |
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, 40); | |
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_5, 40); | |
// LL_TIM_EnableDMAReq_CC2(TIM8); | |
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4); | |
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_5); | |
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_4); | |
// LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_4); | |
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_5); | |
// LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_5); | |
LL_TIM_EnableDMAReq_CC2(TIM8); | |
// NVIC_SetPriority(DMA1_Channel4_IRQn, 3); | |
// NVIC_EnableIRQ(DMA1_Channel4_IRQn); | |
NVIC_SetPriority(DMA1_Channel5_IRQn, 3); | |
NVIC_EnableIRQ(DMA1_Channel5_IRQn); | |
} | |
void DMA1_Channel4_IRQHandler(void) { | |
/* Check whether DMA transfer complete caused the DMA interruption */ | |
if (LL_DMA_IsActiveFlag_TC4(DMA1) == 1) { | |
/* Clear flag DMA transfer complete */ | |
LL_DMA_ClearFlag_TC4(DMA1); | |
// LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4); | |
} | |
/* Check whether DMA half transfer caused the DMA interruption */ | |
if (LL_DMA_IsActiveFlag_HT4(DMA1) == 1) { | |
/* Clear flag DMA half transfer */ | |
LL_DMA_ClearFlag_HT4(DMA1); | |
} | |
if (LL_DMA_IsActiveFlag_TE4(DMA1) == 1) { | |
/* Clear flag DMA transfer error */ | |
LL_DMA_ClearFlag_TE4(DMA1); | |
} | |
} | |
void DMA1_Channel5_IRQHandler(void) { | |
int i; | |
static uint32_t oldPos; | |
uint32_t pos = 0; | |
int32_t dir = 0; | |
/* Check whether DMA transfer complete caused the DMA interruption */ | |
if (LL_DMA_IsActiveFlag_TC5(DMA1) == 1) { | |
/* Clear flag DMA transfer complete */ | |
LL_DMA_ClearFlag_TC5(DMA1); | |
for (i = 0; i < 16; i++) { | |
pos <<= 1; | |
if (dmaInData[7 + (i * 2)] & M1_ENCODER_MISO_Pin) { | |
pos |= 1; | |
} | |
} | |
position = (pos & 0x3FFF); | |
dir = position - oldPos; | |
if (dir > 8000) { | |
dir -= 0x3FFF; | |
} else if (dir < -8000) { | |
dir += 0x3FFF; | |
} | |
direction = dir; | |
oldPos = position; | |
// LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4); | |
} | |
/* Check whether DMA half transfer caused the DMA interruption */ | |
if (LL_DMA_IsActiveFlag_HT5(DMA1) == 1) { | |
/* Clear flag DMA half transfer */ | |
LL_DMA_ClearFlag_HT5(DMA1); | |
} | |
if (LL_DMA_IsActiveFlag_TE5(DMA1) == 1) { | |
/* Clear flag DMA transfer error */ | |
LL_DMA_ClearFlag_TE5(DMA1); | |
} | |
} | |
// MagneticSensorSPI(int cs, float _bit_resolution, int _angle_register) | |
// cs - SPI chip select pin | |
// _bit_resolution sensor resolution bit number | |
// _angle_register - (optional) angle read register - default 0x3FFF | |
MagneticSensorAS5048::MagneticSensorAS5048(void){ | |
} | |
void MagneticSensorAS5048::init(void){ | |
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMAMUX1); | |
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); | |
MX_GPIO_Init(); | |
__enable_irq(); | |
MX_TIM8_Init(); | |
this->Sensor::init(); // call base class init | |
} | |
// Shaft angle calculation | |
// angle is in radians [rad] | |
float MagneticSensorAS5048::getSensorAngle(){ | |
return (position / (float)0x4000) * _2PI; | |
} | |
// function reading the raw counter of the magnetic sensor | |
int MagneticSensorAS5048::getRawCount(){ | |
return (int)position; | |
} | |
/** | |
* Closes the SPI connection | |
* SPI has an internal SPI-device counter, for each init()-call the close() function must be called exactly 1 time | |
*/ | |
void MagneticSensorAS5048::close(){ | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef MAGNETICSENSORAS5048_LIB_H | |
#define MAGNETICSENSORAS5048_LIB_H | |
#include "Arduino.h" | |
#include <SPI.h> | |
#include "../common/base_classes/Sensor.h" | |
#include "../common/foc_utils.h" | |
#include "../common/time_utils.h" | |
#define DEF_ANGLE_REGISTER 0x3FFF | |
class MagneticSensorAS5048: public Sensor{ | |
public: | |
/** | |
* MagneticSensorSPI class constructor | |
* @param cs SPI chip select pin | |
* @param bit_resolution sensor resolution bit number | |
* @param angle_register (optional) angle read register - default 0x3FFF | |
*/ | |
MagneticSensorAS5048(void); | |
/** sensor initialise pins */ | |
void init(void); | |
// implementation of abstract functions of the Sensor class | |
/** get current angle (rad) */ | |
float getSensorAngle() override; | |
int getRawCount(); | |
private: | |
// spi variables | |
int angle_register; //!< SPI angle register to read | |
int chip_select_pin; //!< SPI chip select pin | |
int clock_pin; | |
int miso_pin; | |
// spi functions | |
/** Stop SPI communication */ | |
void close(); | |
/** Calculate parity value */ | |
byte spiCalcEvenParity(word value); | |
/** | |
* Function getting current angle register value | |
* it uses angle_register variable | |
*/ | |
// int getRawCount(); | |
int bit_resolution; //!< the number of bites of angle data | |
int command_parity_bit; //!< the bit where parity flag is stored in command | |
int command_rw_bit; //!< the bit where read/write flag is stored in command | |
int data_start_bit; //!< the the position of first bit | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment