Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@kasperkamperman
Last active August 18, 2022 08:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save kasperkamperman/ee518512a9cfbcfa402ef96d5a3050bd to your computer and use it in GitHub Desktop.
Save kasperkamperman/ee518512a9cfbcfa402ef96d5a3050bd to your computer and use it in GitHub Desktop.
DMA control of GPIO pins on Particle Photon STM32
#include "Particle.h"
// RM0033 MANUAL - Table 23 / Figure 1 System architecture
// Photon is STM32F205
// Only DMA2 is connected with GPIO ports https://stackoverflow.com/questions/46613053/pwm-dma-to-a-whole-gpio
// GPIO BSSRL/BSSRH/BSSR http://hertaville.com/stm32f0-gpio-tutorial-part-1.html
// DMA_Mode_Circular https://github.com/monkbroc/particle-speaker
// Ulrich Radig OctoArtnetNode https://www.ulrichradig.de/home/index.php/dmx/8-kanal-art-net
// Thanks to Julien Vanier for the idea of BSRR manipulation.
// The timers connected to APB2 are clocked from TIMxCLK up to 120 MHz
// In case of the Photon: TIM1, TIM8.
//SYSTEM_MODE(MANUAL); // only use this when you build local
// D7 is GPIO pin 13 on GPIOA.
uint16_t pinMask = 1<<13; // pin 13 on GPIOA (same as 0b0010000000000000)
uint16_t bufferSize = 4;
uint16_t blink_turnhigh_buffer[4];
uint32_t blink_bsrr_buffer0[4];
uint32_t blink_bsrr_buffer1[4]; // double buffer
void timerInit();
void dmaInit();
void setup() { // Put setup code here to run once
delay(2000);
Serial.begin(57600);
timerInit();
dmaInit();
pinMode(D7, OUTPUT);
//WiFi.off();
// D7 is GPIO pin 13 on GPIOA.
// of course you can modify multiple pins if you want
// for example 0b0000000010100000 would turn on A3 and A5 (don't forget to modify the pinMask);
blink_turnhigh_buffer[0] = 1<<13; //(same as 0b0010000000000000)
blink_turnhigh_buffer[1] = 0;
blink_turnhigh_buffer[2] = 1<<13;
blink_turnhigh_buffer[3] = 0;
// We use a XOR operation to mask and make the turn to LOW register low
// (Done by sending a one. )
for(int i = 0; i < 4; i++) {
blink_bsrr_buffer0[i] = blink_turnhigh_buffer[i] + ((blink_turnhigh_buffer[i] ^ pinMask) << 16);
blink_bsrr_buffer1[i] = blink_bsrr_buffer0[i]; // double buffer
}
}
void loop() {
}
void timerInit (void) {
// https://github.com/pkourany/SparkIntervalTimer/blob/master/src/SparkIntervalTimer.cpp
// tryout with a slow timer. 2Hz (so each number is 0.5ms)
//const uint16_t SIT_PRESCALERu = (uint16_t)(SYSCORECLOCK / 1000000UL) - 1; //To get TIM counter clock = 1MHz
const uint16_t SIT_PRESCALERm = (uint16_t)(SystemCoreClock / 2000UL) - 1; //To get TIM counter clock = 2KHz
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_DeInit(TIM8);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = SIT_PRESCALERm;
//TIM_TimeBaseStructure.TIM_Prescaler = SIT_PRESCALERu;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 2000;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM8,&TIM_TimeBaseStructure);
TIM_ClearFlag(TIM8,TIM_FLAG_Update);
TIM_Cmd(TIM8, ENABLE);
}
void dmaInit(void) {
// DMA2 only connects to GPIO ports...
// DMA2 channel 7 stream 1 connects to TIM8_UP
DMA_InitTypeDef DMA_InitStructure;
// Clock enable
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_Cmd(DMA2_Stream1, DISABLE);
DMA_DeInit(DMA2_Stream1);
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_Channel = DMA_Channel_7;
DMA_InitStructure.DMA_PeripheralBaseAddr = ((uint32_t)&(GPIOA->BSRRL));
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) blink_bsrr_buffer0;
DMA_InitStructure.DMA_BufferSize = bufferSize;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
/* Configure double buffering */
DMA_DoubleBufferModeConfig(DMA2_Stream1, (uint32_t) blink_bsrr_buffer1, DMA_Memory_1);
DMA_DoubleBufferModeCmd(DMA2_Stream1, ENABLE);
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream1, ENABLE);
// DMA-Timer8 enable
TIM_DMACmd(TIM8,TIM_DMA_Update,ENABLE);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment