Skip to content

Instantly share code, notes, and snippets.

@friesendrywall
Created April 9, 2025 13:14
Show Gist options
  • Save friesendrywall/b6d7e7af07f7e89eb851784bf3893c5d to your computer and use it in GitHub Desktop.
Save friesendrywall/b6d7e7af07f7e89eb851784bf3893c5d to your computer and use it in GitHub Desktop.
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(){
}
#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