DMA SPI on STM32F030F4 - Page 1
Forum section: electronics / general

author: CM800
author_rank: Frequent Contributor
timestamp: February 11, 2017, 04:28:24 pm
content: Hi All,I'm trying to get going with the STM32F0 in effort to move away from Arduino. I'm using visual GDB and so far it's been great.Now, I've managed to get all my GPIO working just fine.. Now I'm trying to branch away and learn to use peripherals.I figured the best place to start would be SPI so I cracked out my logic analyser and hooked that up too..Now. I'm trying to get programming, honestly... I don't know where to start.Does anyone have any good guides for getting familiar with ARM programming, specifically Cortex M0 for now..I'm getting confused with the number of options, for example:DMA_InitTypeDefDMA_HandleTypeDef(Which one do I need to use?)I just kind of feel I'm running about in the blind not sure where to start.I just want to get a simple SPI comms running, sending out data to read from my Logic Analyser.After that, get two boards talking to eachother through SPI (circling data so there is a switch on one and an led on the other board)What I've got so far:Code:#include <stm32f0xx_hal.h>#ifdef __cplusplusextern "C"#endifvoid SysTick_Handler(void){HAL_IncTick();HAL_SYSTICK_IRQHandler();}u_int8_t data;int main(void){HAL_Init();data = {0x01, 0x03, 0xF0, 0xFF, 0xDA, 0x1A, 0xF1, 0xBD};__GPIOA_CLK_ENABLE();__SPI1_CLK_ENABLE();__DMA1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStructure;/*====================================================================== SPI================================================================*//*SPI1_MISO = PA6SPI1_MOSI = PA7SPI1_SCLK = PA5*/GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;GPIO_InitStructure.Alternate = GPIO_AF0_SPI1;GPIO_InitStructure.Pin = GPIO_PIN_5;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.Pin = GPIO_PIN_6;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.Pin = GPIO_PIN_7;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);SPI_HandleTypeDef hspi;HAL_SPI_MspInit(&hspi);for (;;){}}I Admit I had written some more, however I deleted it as I felt I was going in the wrong direction and didn't know what I was really typing.Most tutorials I found were for the F4 and F3 and didn't seem to be much use.

author: newbrain
author_rank: Super Contributor
timestamp: February 13, 2017, 06:46:51 pm
content: Hi CM800,not much love for your question, it would seem...I'm also an user of VisualGDB, and find it quite comfortable to use.Your code shows that, while you have a good grasp of GPIO initialization, your understanding of the initialization sequence for other HAL peripherals is a bit lacking.Before tackling DMA, perhaps, you should follow and try some examples with regular (polled) I/O.With the HAL it goes like this (where PPP is a generic peripheral different from GPIO):Declare an handle variable; the HAL keeps state in it, so its lifetime must be sufficient: in general, staticSet the Handle Instance member to the specific peripheralFill in the Init structure inside the Handle (this answer your question, in general) with the specific peripheral settingsCall the HAL_PPP_Init() function with the address of your handleThe init function will call HAL_PPP_MspInit(), so you need to define it and put the low level initialization (GPIO pinsand clock) thereAlternatively, you can ignore the MspInit (an empty__weakone is provided by default) and do the GPIO initialization outside (as in your code)Clocksfor the peripheralare turned on by HAL_PPP_Init(), no need to do it yourselfCode:/* SPI handler declaration */SPI_HandleTypeDef SpiHandle;int main(void){/* Select SPI */SpiHandle.Instance = SPI1;/* All the peripheral settings */SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;SpiHandle.Init.CRCPolynomial = 7;SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;SpiHandle.Init.NSS = SPI_NSS_SOFT;SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;SpiHandle.Init.CRCLength = SPI_CRC_LENGTH_8BIT;SpiHandle.Init.Mode = SPI_MODE_MASTER;HAL_SPI_Init(&SpiHandle); /* Maybe check result code! *//* etc. etc. */for(;;);}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){GPIO_InitTypeDef GPIO_InitStruct;if(hspi->Instance == SPI1) /* You might have more than one SPI active, each needs its own pins! */{/* Your GPIO initialization for this SPI */}}Since you use VisualGDB, I'm sure you have downloaded the relevant BSP for the STM32s, so you have a lot of examples at hand, including many with SPI and DMA.Just copy this path in a Windows Explorer location bar:Code:%LOCALAPPDATA%\VisualGDB\EmbeddedBSPs\arm-eabi\com.sysprogs.arm.stm32\VendorSamples\STM32Cube_FW_F0_V1.7.0\ProjectsFrom there, you can find all the examples for your board.

author: mark03
author_rank: Frequent Contributor
timestamp: February 13, 2017, 06:58:48 pm
content: If your goal is to understand the platform and get your feet wet, my suggestion would be to strip out the HAL entirely and use nothing above the CMSIS register definitions; these will be in stm32f030.h or some such. In your code, just access the registers directly using the symbolic names for the registers and their bitfields, e.g.SPI1->CR |= SPI1_CR_SPE;SPI1->CR &= ~SPI1_CR_SPE;to set or clear the enable bit on SPI1.This will be slower at first, but it has the considerable advantage that once you get something working, you will understand it completely. It also means you only need a single document open as you code, the Reference Manual for your particular ST part. I find this actually reduces my overall cognitive burden, versus using the HAL.You can start with a very simple program (blinking LED) and then rebuild/check periodically as you replace the HAL dependencies with direct register accesses. You may wish to keep the HAL calls that configure the processor clocks, until you feel comfortable enough to dig into the RCC registers and write your own.Please note, mine is a contrarian opinion. Someone more sensible will be along shortly to give you advice, but FWIW, I do this for a living.

author: newbrain
author_rank: Super Contributor
timestamp: February 13, 2017, 07:43:59 pm
content: Quote from: mark03 on February 13, 2017, 06:58:48 pmFrom what I have been reading here, I'd say that's anything but a minority opinion!I do not do this for a living (long time I do not write code at work), so my opinion is from an hobbyist point of view.I actually started with the HAL, while reading the RMs (F429) front to back.Now I freely mix it with direct register access, according to my needs.I find HAL initialization routines handy, especially when dealing with more complicated peripherals, but parts of it are brain-dead (UART receive).The CubeMX application is handy to generate a framework and initialize the clock chains, and assists in moving from one MCU to another.The most complex application I have coded with HAL is a F746 Disco based oscilloscope.Encoder & touch screen for the UI, LCD controller and DMA2D, interleaved ADCs with DMA, double buffering, external RAM...Had I to write it with pure direct register access, I'd still be battling to bring up a trace...

author: CM800
author_rank: Frequent Contributor
timestamp: February 13, 2017, 08:08:54 pm
content: Quote from: newbrain on February 13, 2017, 06:46:51 pmThanks for your support!I've tried out this, writing the code myself, but I'm surely not getting anything out!Do I need to Enable the SPI?Also how do I transmit, I've tried HAL_SPI_Transmit() but it's saying there is no matching function dispite being listed by Intellisense.Current code:Code:#include <stm32f0xx_hal.h>#ifdef __cplusplusextern "C"#endifvoid SysTick_Handler(void){HAL_IncTick();HAL_SYSTICK_IRQHandler();}SPI_HandleTypeDef SpiHandle;void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){GPIO_InitTypeDef GPIO_InitStruct;if (hspi->Instance == SPI1) /* You might have more than one SPI active, each needs its own pins! */{GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);}}int main(void){HAL_Init();__GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.Pin = GPIO_PIN_4;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);/*=========================================================================SPI Setup=========================================================================*/SpiHandle.Instance = SPI1;SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;SpiHandle.Init.CRCPolynomial = 7;SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;SpiHandle.Init.Mode = SPI_MODE_MASTER;SpiHandle.Init.NSS = SPI_NSS_SOFT;SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;HAL_SPI_Init(&SpiHandle);u_int8_t data = {0x06, 0xAA, 0xBB, 0xCF, 0xDD, 0xDA, 0xDB, 0xFA};for (;;){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_SPI_Transmit(&SpiHandle.Init, &data, 8, 100);HAL_Delay(500);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_Delay(500);}}

author: Jeroen3
author_rank: Super Contributor
timestamp: February 13, 2017, 09:12:51 pm
content: Ask the cube to get the PLL running. Or steal this from an example.1. Enable gpio. (In rcc)2. Setup gpio accordingly. Multiplexors and input modes. GPIOx-CR probably. Maybe a remap. Read manual for modes.3. Enable spi clock (RCC)4. Setup spi. Speed, width, polarity.5. Enable spi.6. Write DR to srnd. Read DR to read what was shifted in with last send.Dma is even easier, if you don't allow yourself to become distracted by the HAL.

author: newbrain
author_rank: Super Contributor
timestamp: February 13, 2017, 09:13:09 pm
content: My fault, sorryI went from memory...instead of checking the code I was copying from.You actually have to enable the peripheral clock, too (e.g. in the MspInit())What is not needed is enabling the peripheral itself.Your HAL_SPI_Transmit() does not match probably because you used &SpiHandle.Init, the required parameter is &SpiHandle: an SPI_HandleTypeDef *, not a SPI_InitTypeDef*.Most of the HAL functions take an handle pointer as first argument (GPIO is much simpler, as you have seen).

author: CM800
author_rank: Frequent Contributor
timestamp: February 13, 2017, 09:44:46 pm
content: Thanks for the help everyone It's been really useful:Code:#include <stm32f0xx_hal.h>#ifdef __cplusplusextern "C"#endifvoid SysTick_Handler(void){HAL_IncTick();HAL_SYSTICK_IRQHandler();}SPI_HandleTypeDef SpiHandle;void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){GPIO_InitTypeDef GPIO_InitStruct;if (hspi->Instance == SPI1) /* You might have more than one SPI active, each needs its own pins! */{GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Pin = GPIO_PIN_5;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_6;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_7;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);}}int main(void){HAL_Init();__GPIOA_CLK_ENABLE();__SPI1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.Pin = GPIO_PIN_4;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);/*=========================================================================SPI Setup=========================================================================*/SpiHandle.Instance = SPI1;SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;SpiHandle.Init.CRCPolynomial = 7;SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;SpiHandle.Init.Mode = SPI_MODE_MASTER;SpiHandle.Init.NSS = SPI_NSS_SOFT;SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;HAL_SPI_Init(&SpiHandle);u_int8_t data = {0x06, 0xAA, 0xBB, 0xCF, 0xDD, 0xDA, 0xDB, 0xFA};u_int8_t dat = 0xFF;for (;;){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);SpiHandle.Instance = SPI1;HAL_SPI_Transmit(&SpiHandle, &data, 8, 10); /// I THINK THIS IS RIGHT??HAL_Delay(500);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_Delay(500);}}Here we go!Moving from there, how may I go about DMA?I'd like to have something like an array of bytes (say 8 or 16 bytes)and just shoot them off and not have to worry so my processor can handle something else for example.What I really want to get going is comms with an CPLD.

author: voltsandjolts
author_rank: Unknown
timestamp: February 13, 2017, 10:23:23 pm
content: That Logic Analyser display looks quite nice - what is it?

author: CM800
author_rank: Frequent Contributor
timestamp: February 13, 2017, 10:58:10 pm
content: Quote from: voltsandjolts on February 13, 2017, 10:23:23 pmIt's A ZeroPlus Logic CubeMine was gifted to us with a used oscilloscope.I've looked around, they go for about £1k. I've seen a few for £120 - £300 too though I don't know if they are scams (though that would be weird. Maybe fake products? Idk...)

author: Jeroen3
author_rank: Super Contributor
timestamp: February 14, 2017, 07:43:24 am
content: Quote from: CM800 on February 13, 2017, 09:44:46 pmFind the DMA channel connected.Enable the DMA clock.Write source/terget pointer.Set source target width and type. Set circular, if applicable.Set how many.Enable the channel.Enable spi DMAEN.Write is easy, will start immediately. Read will also require a write.Or use the Hal spi with dma function.

author: CM800
author_rank: Frequent Contributor
timestamp: February 14, 2017, 06:34:37 pm
content: Quote from: Jeroen3 on February 14, 2017, 07:43:24 amSounds easier then it looks....____Find the DMA channel connected.____Enable the DMA clock.[ ]____Write source/terget pointer. (Where?)[ ]____Set source target width and type.(Where?) Set circular, if applicable.[ ]____Set how many. ()Enable the channel.Enable spi DMAEN.I'm finding there to be so little documentation online for these peripherals for the M0, It's doing my nut in as I should be able to do this by now... Augh!Code:#include <stm32f0xx_hal.h>#ifdef __cplusplusextern "C"#endifvoid SysTick_Handler(void){HAL_IncTick();HAL_SYSTICK_IRQHandler();}SPI_HandleTypeDef SpiHandle;DMA_HandleTypeDef DMAHandle;void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){GPIO_InitTypeDef GPIO_InitStruct;if (hspi->Instance == SPI1) /* You might have more than one SPI active, each needs its own pins! */{GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Pin = GPIO_PIN_5;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_6;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_7;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);__SPI1_CLK_ENABLE();}}u_int8_t data = { 'H', 'E', 'L', 'L', 'O', ' ', ':', ')' };int main(void){HAL_Init();__GPIOA_CLK_ENABLE();__DMA1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.Pin = GPIO_PIN_4;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);/*=========================================================================SPI Setup=========================================================================*/SpiHandle.Instance = SPI1;SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;SpiHandle.Init.CRCPolynomial = 7;SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;SpiHandle.Init.Mode = SPI_MODE_MASTER;SpiHandle.Init.NSS = SPI_NSS_SOFT;SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;HAL_SPI_Init(&SpiHandle);/*=========================================================================DMA Setup=========================================================================*/DMAHandle.DmaBaseAddress = DMA1;DMAHandle.ChannelIndex = 0;DMAHandle.Instance = DMA1_Channel3;DMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;DMAHandle.Init.MemDataAlignment = 8;DMAHandle.Init.MemInc = DMA_MINC_ENABLE;DMAHandle.Init.PeriphDataAlignment = 1;DMAHandle.Init.PeriphInc = DMA_MINC_DISABLE;DMAHandle.Init.Mode = DMA_CIRCULAR;DMAHandle.Init.Priority = DMA_PRIORITY_HIGH;for (;;){HAL_GPIO_WritePin(GPIO_InitStructure, GPIO_PIN_4, GPIO_PIN_SET);DMA_SpiHandle.Instance = SPI1;HAL_SPI_Transmit(&SpiHandle, &data, 8, 10);HAL_Delay(500);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_Delay(500);}}

author: Jeroen3
author_rank: Super Contributor
timestamp: February 14, 2017, 08:19:52 pm
content: Here:http://www.st.com/content/ccc/resource/technical/document/reference_manual/cf/10/a8/c4/29/fb/4c/42/DM00091010.pdf/files/DM00091010.pdf/jcr:content/translations/en.DM00091010.pdfEach channel has 5 registers.DMA->CCR, with controls, such as enable, width and circular.DMA->CMAR, memory addres. (Beware of alignment)DMA->CPAR, peripheral address. Or memory in mem-to-mem.DMA->CNDTR, transaction counter.DMA->ISR, interrupt and status flags.This should clear things up. Dma is super easy.Cmar = &uint64_t[].(Explicitely a large type to force alignment, although this does not matter with bytes, it does with (half) words.)Cpar = &spi->dr.Cndtr = 10Ccr = MINC + EN.Spi->cr = dma TXEN.Writes 10 bytes to spi.

author: CM800
author_rank: Frequent Contributor
timestamp: February 14, 2017, 09:01:49 pm
content: Quote from: Jeroen3 on February 14, 2017, 08:19:52 pmI'm trying to get my head around this, because there seems to be much more to it in the HAL like:Code:DMAHandle.DmaBaseAddress = DMA1;DMAHandle.ChannelIndex = 0;DMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;DMAHandle.Init.MemDataAlignment = 8;DMAHandle.Init.MemInc = DMA_MINC_ENABLE;DMAHandle.Init.PeriphDataAlignment = 1;DMAHandle.Init.PeriphInc = DMA_MINC_DISABLE;DMAHandle.Init.Mode = DMA_CIRCULAR;DMAHandle.Init.Priority = DMA_PRIORITY_HIGH;DMAHandle.Instance->CCR = DMA_CCR_MINC | DMA_CCR_EN;DMAHandle.Instance->CMAR = (uint32_t) &data;DMAHandle.Instance->CNDTR = 8;DMAHandle.Instance->CPAR = SPI1->DR;Also there seems to be an instance in the SPI setup handle?like this:Code:SpiHandle.hdmatx->Init.Direction = DMA_MEMORY_TO_PERIPH;SpiHandle.hdmatx->Init.MemDataAlignment = 8;SpiHandle.hdmatx->Init.MemInc = DMA_MINC_ENABLE;SpiHandle.hdmatx->Init.Mode = DMA_CIRCULAR;SpiHandle.hdmatx->Init.PeriphDataAlignment = 1;SpiHandle.hdmatx->Init.PeriphInc = DMA_MINC_DISABLE;SpiHandle.hdmatx->Init.Mode = DMA_CIRCULAR;SpiHandle.hdmatx->Init.Priority = DMA_PRIORITY_HIGH;

author: mark03
author_rank: Frequent Contributor
timestamp: February 14, 2017, 10:12:02 pm
content: You could always just ditch the HALBut in any case, all of those DMA init struct fields correspond directly to bitfields in the DMA registers. It's not hard to set up; just follow the steps in "Channel configuration procedure" under section 10.3.3.The only really confusing thing about STM32 DMA is that "circular mode" isn't. It should be called auto-restart or something else. This is because the memory and peripheral addresses in CMAR/CPAR do not increment over the course of a DMA sequence. They remain fixed in the registers as base addresses. If the DMA is ever stopped and restarted, it will not pick up from where it left off, but rather start afresh from CMAR/CPAR. This makes it almost impossible to use "circular mode" for implementing a circular buffer, because you cannot safely write to the buffer while a DMA is in progress, and temporarily halting the DMA will cause it to lose its place.

author: voltsandjolts
author_rank: Unknown
timestamp: February 14, 2017, 10:25:31 pm
content: Yeh, forget about DMA Circular Mode until you're comfortable with the simpler modes.Circular mode does work well for read-only ring buffers though - as in comms receive buffers.

author: CM800
author_rank: Frequent Contributor
timestamp: February 15, 2017, 07:16:31 am
content: I appreciate your suggestions so far, but I'm still stuck with nowhere to goThis is my code, It's not working. I'm pulling my hair out here.I really want to try stick to HAL. I've tried your suggestions of doing the registers directly but I'm still getting nowhere.I feel like I'm being given half the solution, problem is, you either get it all right, or if you miss a single thing it doesn't work.Naturally I get nothing out and the MCU is frozen with the blinking LED high.Code:#include <stm32f0xx_hal.h>#ifdef __cplusplusextern "C"#endifvoid SysTick_Handler(void){HAL_IncTick();HAL_SYSTICK_IRQHandler();}SPI_HandleTypeDef SpiHandle;DMA_HandleTypeDef DMAHandle;void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){GPIO_InitTypeDef GPIO_InitStruct;if (hspi->Instance == SPI1) /* You might have more than one SPI active, each needs its own pins! */{GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Pin = GPIO_PIN_5;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_6;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_7;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);__SPI1_CLK_ENABLE();}}u_int8_t data = { 'H', 'E', 'L', 'L', 'O', ' ', ':', ')' };int main(void){HAL_Init();__GPIOA_CLK_ENABLE();__DMA1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.Pin = GPIO_PIN_4;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);/*=========================================================================SPI Setup=========================================================================*/SpiHandle.Instance = SPI1;SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;SpiHandle.Init.CRCPolynomial = 7;SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;SpiHandle.Init.Mode = SPI_MODE_MASTER;SpiHandle.Init.NSS = SPI_NSS_SOFT;SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;HAL_SPI_Init(&SpiHandle);/*=========================================================================DMA Setup=========================================================================*/DMAHandle.DmaBaseAddress = DMA1;DMAHandle.ChannelIndex = 3;DMAHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;DMAHandle.Init.MemInc = DMA_MINC_ENABLE;DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;DMAHandle.Init.PeriphInc = DMA_MINC_DISABLE;DMAHandle.Init.Mode = DMA_NORMAL;DMAHandle.Init.Priority = DMA_PRIORITY_HIGH;DMAHandle.Instance->CMAR = (uint32_t) &data;DMAHandle.Instance->CNDTR = 8;DMAHandle.Instance->CPAR = SPI1->DR;HAL_DMA_Init(&DMAHandle);for (;;){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_DMA_Start(&DMAHandle, (uint32_t)&data, SPI1->DR, 8);//SpiHandle.Instance = SPI1;//HAL_SPI_Transmit(&SpiHandle, &data, 8, 10);HAL_Delay(500);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_Delay(500);}}

author: voltsandjolts
author_rank: Unknown
timestamp: February 15, 2017, 10:51:59 am
content: You are not calling your function HAL_SPI_MspInit() which might be part of the problem (Edit: or maybe thats called from HAL_SPI_Init?). At a glance, you look to be on the right track though, so keep at it!This sends some bytes by DMA to SPI1 on STM32L0 (verified on hardware) and might help you (although I cheated and used STM Cube):Code:/********************************************************************************* File Name : main.c* Description : Main program body******************************************************************************** COPYRIGHT(c) 2017 STMicroelectronics** Redistribution and use in source and binary forms, with or without modification,* are permitted provided that the following conditions are met:* 1. Redistributions of source code must retain the above copyright notice,* this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright notice,* this list of conditions and the following disclaimer in the documentation* and/or other materials provided with the distribution.* 3. Neither the name of STMicroelectronics nor the names of its contributors* may be used to endorse or promote products derived from this software* without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.********************************************************************************//* Includes ------------------------------------------------------------------*/#include "main.h"#include "stm32l0xx_hal.h"/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private variables ---------------------------------------------------------*/SPI_HandleTypeDef hspi1;DMA_HandleTypeDef hdma_spi1_tx;/* USER CODE BEGIN PV *//* Private variables ---------------------------------------------------------*//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);void Error_Handler(void);static void MX_GPIO_Init(void);static void MX_DMA_Init(void);static void MX_SPI1_Init(void);/* USER CODE BEGIN PFP *//* Private function prototypes -----------------------------------------------*//* USER CODE END PFP *//* USER CODE BEGIN 0 *//* USER CODE END 0 */int main(void){/* USER CODE BEGIN 1 */uint8_t buf[] = {1,2,3,4,5,6,7,8,9};/* USER CODE END 1 *//* MCU Configuration----------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_SPI1_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_SPI_Transmit_DMA(&hspi1,buf,sizeof(buf));HAL_Delay(100);HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */}/** System Clock Configuration*/void SystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct;RCC_ClkInitTypeDef RCC_ClkInitStruct;/**Configure the main internal regulator output voltage*/__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);/**Initializes the CPU, AHB and APB busses clocks*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;RCC_OscInitStruct.MSIState = RCC_MSI_ON;RCC_OscInitStruct.MSICalibrationValue = 0;RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/**Initializes the CPU, AHB and APB busses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;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_0) != HAL_OK){Error_Handler();}/**Configure the Systick interrupt time*/HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);/**Configure the Systick*/HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);/* SysTick_IRQn interrupt configuration */HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);}/* SPI1 init function */static void MX_SPI1_Init(void){hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;hspi1.Init.Direction = SPI_DIRECTION_2LINES;hspi1.Init.DataSize = SPI_DATASIZE_8BIT;hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;hspi1.Init.NSS = SPI_NSS_SOFT;hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi1.Init.TIMode = SPI_TIMODE_DISABLE;hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi1.Init.CRCPolynomial = 7;if (HAL_SPI_Init(&hspi1) != HAL_OK){Error_Handler();}}/*** Enable DMA controller clock*/static void MX_DMA_Init(void){/* DMA controller clock enable */__HAL_RCC_DMA1_CLK_ENABLE();/* DMA interrupt init *//* DMA1_Channel2_3_IRQn interrupt configuration */HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);}/** Configure pins as* Analog* Input* Output* EVENT_OUT* EXTIPA2 ------> USART2_TXPA3 ------> USART2_RX*/static void MX_GPIO_Init(void){GPIO_InitTypeDef GPIO_InitStruct;/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin : B1_Pin */GPIO_InitStruct.Pin = B1_Pin;GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pins : USART_TX_Pin USART_RX_Pin */GPIO_InitStruct.Pin = USART_TX_Pin|USART_RX_Pin;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF4_USART2;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin : LD2_Pin */GPIO_InitStruct.Pin = LD2_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @param None* @retval None*/void Error_Handler(void){/* USER CODE BEGIN Error_Handler *//* User can add his own implementation to report the HAL error return state */while(1){}/* USER CODE END Error_Handler */}#ifdef USE_FULL_ASSERT/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/void assert_failed(uint8_t* file, uint32_t line){/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */}#endif/*** @}*//*** @}*//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/You also need a call to __HAL_LINKDMA like this:Code:void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi){GPIO_InitTypeDef GPIO_InitStruct;if(hspi->Instance==SPI1){/* USER CODE BEGIN SPI1_MspInit 0 *//* USER CODE END SPI1_MspInit 0 *//* Peripheral clock enable */__HAL_RCC_SPI1_CLK_ENABLE();/**SPI1 GPIO ConfigurationPA7 ------> SPI1_MOSIPB3 ------> SPI1_SCK*/GPIO_InitStruct.Pin = GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_3;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* Peripheral DMA init*/hdma_spi1_tx.Instance = DMA1_Channel3;hdma_spi1_tx.Init.Request = DMA_REQUEST_1;hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_spi1_tx.Init.Mode = DMA_NORMAL;hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK){Error_Handler();}__HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);/* USER CODE BEGIN SPI1_MspInit 1 *//* USER CODE END SPI1_MspInit 1 */}}I'd recommend you try STM Cube, even if just using it to copy relevant code to your own project. Makes it easier to get started.

author: CM800
author_rank: Frequent Contributor
timestamp: February 15, 2017, 04:39:43 pm
content: Okay, I've been trying this after going through that code you showed me a whole number of times.I'm still missing something...Code:#include <stm32f0xx_hal.h>#ifdef __cplusplusextern "C"#endifvoid SysTick_Handler(void){HAL_IncTick();HAL_SYSTICK_IRQHandler();}SPI_HandleTypeDef SpiHandle;DMA_HandleTypeDef DMAHandle;void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){GPIO_InitTypeDef GPIO_InitStruct;if (hspi->Instance == SPI1) /* You might have more than one SPI active, each needs its own pins! */{GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Pin = GPIO_PIN_5;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_6;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_7;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);__SPI1_CLK_ENABLE();}}u_int8_t data = { 'H', 'E', 'L', 'L', 'O', ' ', ':', ')' };int main(void){HAL_Init();__GPIOA_CLK_ENABLE();__DMA1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.Pin = GPIO_PIN_4;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.Pin = GPIO_PIN_1;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.Pin = GPIO_PIN_2;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);/*=========================================================================SPI Setup=========================================================================*/SpiHandle.Instance = SPI1;SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;SpiHandle.Init.CRCPolynomial = 7;SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;SpiHandle.Init.Mode = SPI_MODE_MASTER;SpiHandle.Init.NSS = SPI_NSS_SOFT;SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;HAL_SPI_Init(&SpiHandle);/*=========================================================================DMA Setup=========================================================================*/DMAHandle.Instance = DMA1_Channel3;DMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;DMAHandle.Init.MemInc = DMA_MINC_ENABLE;DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE;DMAHandle.Init.Mode = DMA_NORMAL;DMAHandle.Init.Priority = DMA_PRIORITY_HIGH;HAL_DMA_Init(&DMAHandle);//HAL_Delay(200);__HAL_LINKDMA(&SpiHandle, hdmatx, DMAHandle);//HAL_Delay(200);HAL_Delay(1000);for (;;){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_SPI_Transmit_DMA(&SpiHandle, &data, sizeof(data));if (data < 255){data += 1;}else{data = 0;}//HAL_SPI_DMAResume(&SpiHandle);SpiHandle.Instance = SPI1;//HAL_SPI_Transmit(&SpiHandle, &data, 8, 10);HAL_Delay(500);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_Delay(500);}}EDIT:Woah, ok, it just worked... only once though.After it's sent do you need to resume it / give it more data?EDIT2:Okay,I've got some more information on it -not- sending the second time around.Timeline:t0 (beginning): {SPI->SR = 0x00000000}t1(after first DMA send): {SPI->SR = 0x00000002(TX Empty)}t2 (Second time around trying to send):{SPI->SR = 0x00000643(TX FIFO is full)(Overrun occoured)(TX buffer empty)(RX Buffer Not Empty)(Nothing connected to it)}Thoughts?Wow, once you know how to use a debugger / live debugging, everything becomes so much more fun... What was a black box suddenly becomes a puzzle!

author: newbrain
author_rank: Super Contributor
timestamp: February 15, 2017, 10:04:08 pm
content: :-+You almost made it!I had promised to write an answer earlier, but daughter's high school physics (E-field and Gauss' theorem) and Latin (Cicero) tests preparation had, you might imagine, a slightly higher priority...Quote from: voltsandjolts on February 15, 2017, 10:51:59 amThe HAL_PPP_MspInit() functions are called by the HAL. No need to call it yourself.About the code:First, the minor things:Code:if (data < 255){data += 1;}else{data = 0;}This works... but++data;does the same thing and it is idiomatic.The uint8_t is guaranteed to safely roll over after 255, defined behaviour.The following two things are more a question of personal taste, so feel free to disregard them:I prefer usingdatarather than&data, but the meaning is exactly the same.Same thing for sizeof, () are needed only when taking the size of a type, not a variable:sizeof data.Now to the meat of the question:If you use the HAL DMA functions you need to enable interrupts: HAL_PPP_Start/Transmit/etc_DMA() calls are internally using HAL_DMA_Start_IT(), and cleanup of DMA flags (so that they can be ready next time round) is done in the DMA ISR.So, you need to add this:Code:void DMA1_Channel2_3_IRQHandler(void){HAL_DMA_IRQHandler(SpiHandle.hdmatx); // Or you can use &DMAHandle}If you need to provide actions at transfer complete or half complete, you must define the relevant callbacks:Code:void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi);/* or/and */void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi);If you don't, empty __weak ones are provided, no worries.Note that the HAL will be calling the peripheral's regular IRQ callbacks, not the DMA ones!Of course, DMA IRQs must be enabled:Code:/* Do this e.g. after initializing DMAHandle */HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1, 1); /* check the IRQ name, should be correct for F0 */HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);Now, you should be all set.If you don't want to use IRQs, there's the need to poll the DMA for the transfer complete and manually clear the relevant flags, but I never tried (I would not use the HAL then). See chapter 10.3.6, 10.4.1 and 10.4.2 of thereference manual(might need a different RM for your F0).BTW, I don't see a clock chain setup routine, are you HAL_Delay()s working correctly, i.e. the pin toggles at 1Hz when removing the SPI transmit call?Hope this helps,Have fun!

author: CM800
author_rank: Frequent Contributor
timestamp: February 15, 2017, 10:58:06 pm
content: Hi newbrain,Thanks SO MUCH for all your help, I'm glad you took some time out for me at all!I've took your suggestions in, it's still only transmitting at the start.I noticed something I hadn't before.It was getting stuck in an infinite loop that reccomended me to add a macro to find out what IRQ I missed... the same one you recommended!Code:void __attribute__ ((weak)) DMA1_Channel2_3_IRQHandler(){//If you hit the breakpoint below, one of the interrupts was unhandled in your code.//Define the following function in your code to handle it://extern "C" void DMA1_Channel2_3_IRQHandler();asm("bkpt 255");}However it doesn't seem to notice I've added it... not sure what is going on here at all now.Code:#include <stm32f0xx_hal.h>#ifdef __cplusplusextern "C"#endifvoid SysTick_Handler(void){HAL_IncTick();HAL_SYSTICK_IRQHandler();}SPI_HandleTypeDef SpiHandle;DMA_HandleTypeDef DMAHandle;void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){GPIO_InitTypeDef GPIO_InitStruct;if (hspi->Instance == SPI1) /* You might have more than one SPI active, each needs its own pins! */{GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Pin = GPIO_PIN_5;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_6;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_7;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);__SPI1_CLK_ENABLE();}}void DMA1_Channel2_3_IRQHandler(void){HAL_DMA_IRQHandler(SpiHandle.hdmatx); // Or you can use &DMAHandle}u_int8_t data = { 'H', 'E', 'L', 'L', 'O', ' ', ':', ')' };int main(void){HAL_Init();__GPIOA_CLK_ENABLE();__DMA1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.Pin = GPIO_PIN_4;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.Pin = GPIO_PIN_1;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.Pin = GPIO_PIN_2;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);/*=========================================================================SPI Setup=========================================================================*/SpiHandle.Instance = SPI1;SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;SpiHandle.Init.CRCPolynomial = 7;SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;SpiHandle.Init.Mode = SPI_MODE_MASTER;SpiHandle.Init.NSS = SPI_NSS_SOFT;SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;HAL_SPI_Init(&SpiHandle);/*=========================================================================DMA Setup=========================================================================*/DMAHandle.Instance = DMA1_Channel3;DMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;DMAHandle.Init.MemInc = DMA_MINC_ENABLE;DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE;DMAHandle.Init.Mode = DMA_NORMAL;DMAHandle.Init.Priority = DMA_PRIORITY_HIGH;HAL_DMA_Init(&DMAHandle);HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1, 1); /* check the IRQ name, should be correct for F0 */HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);__HAL_LINKDMA(&SpiHandle, hdmatx, DMAHandle);uint8_t datin;for (;;){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);HAL_SPI_Transmit_DMA(&SpiHandle, data, sizeof data);for (uint8_t v = 0; v < sizeof data; v++){if (data == 255){data = 0;}else{data++;}}HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);HAL_Delay(100);}}

author: newbrain
author_rank: Super Contributor
timestamp: February 15, 2017, 11:19:45 pm
content: Are you still hitting that breakpoint?This should not happenMake sure you are compiling this as C, not C++ or add the extern "C" in front of the interrupt service routine.Also, you could try setting set a breakpoint in the DMA ISR and see if you get there...

author: CM800
author_rank: Frequent Contributor
timestamp: February 16, 2017, 06:34:18 am
content: Had to poke around a bit, but here we are!I've got it going finally, huge thanks to everyone for your help!!..... There are few better things then getting a 4k monitor for programming and logic analysers!FINAL WORKING CODE: (for future reference to others travelling this path...)Code:#include <stm32f0xx_hal.h>#ifdef __cplusplusextern "C"#endifvoid SysTick_Handler(void){HAL_IncTick();HAL_SYSTICK_IRQHandler();}SPI_HandleTypeDef SpiHandle;DMA_HandleTypeDef DMAHandle;extern "C" void DMA1_Channel2_3_IRQHandler();void DMA1_Channel2_3_IRQHandler(){HAL_DMA_IRQHandler(SpiHandle.hdmatx); // Or you can use &DMAHandle}void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){GPIO_InitTypeDef GPIO_InitStruct;if (hspi->Instance == SPI1) /* You might have more than one SPI active, each needs its own pins! */{GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Pin = GPIO_PIN_5;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_6;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_7;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);__SPI1_CLK_ENABLE();}}u_int8_t data;int main(void){HAL_Init();__GPIOA_CLK_ENABLE();__DMA1_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.Pin = GPIO_PIN_4;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.Pin = GPIO_PIN_1;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.Pin = GPIO_PIN_2;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);/*=========================================================================SPI Setup=========================================================================*/SpiHandle.Instance = SPI1;SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;SpiHandle.Init.CRCPolynomial = 7;SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;SpiHandle.Init.Mode = SPI_MODE_MASTER;SpiHandle.Init.NSS = SPI_NSS_SOFT;SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;HAL_SPI_Init(&SpiHandle);/*=========================================================================DMA Setup=========================================================================*/DMAHandle.Instance = DMA1_Channel3;DMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;DMAHandle.Init.MemInc = DMA_MINC_ENABLE;DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE;DMAHandle.Init.Mode = DMA_NORMAL;DMAHandle.Init.Priority = DMA_PRIORITY_HIGH;HAL_DMA_Init(&DMAHandle);HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1, 1); /* check the IRQ name, should be correct for F0 */HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);__HAL_LINKDMA(&SpiHandle, hdmatx, DMAHandle);for (size_t i = 0; i < sizeof data; i++){data = i;}uint8_t datin;for (;;){if (SpiHandle.State != HAL_SPI_STATE_BUSY_TX){//HAL_Delay(100);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);HAL_SPI_Transmit_DMA(&SpiHandle, data, sizeof data);//HAL_SPI_Transmit(&SpiHandle, data, sizeof data, 100);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);}}}

author: newbrain
author_rank: Super Contributor
timestamp: February 16, 2017, 08:16:05 am
content: And now you made it!Glad to hear it works, good job!Debugging remotely is always a tad difficult (my closest usable STM32 is about 2500km away), but having gone through more or less the same moves myself, I knew it could be done!I did not propose a state check as your original code had some long delays between the calls, but you figured it out, kudos!An alternative way could be setting a volatile flag in the IRQ callback when done, to signal the main loop that another transmit is possible.Thanks for sharing working code.

author: CM800
author_rank: Frequent Contributor
timestamp: February 16, 2017, 08:28:53 am
content: Got up early and continued on this morning haha, about to go off to work.now I've been trying to get an LCD working with it... a whole new host of problems. I tried porting a library for it over unsuccessfully (managed to get to an error free state, but it just wouldn't play nice)I plan to try some other things today at work.