Last active
August 18, 2022 08:41
-
-
Save kasperkamperman/ee518512a9cfbcfa402ef96d5a3050bd to your computer and use it in GitHub Desktop.
DMA control of GPIO pins on Particle Photon STM32
This file contains 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
#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