I have been working quite a bit with ChibioS recently and am now venturing into DMA for some fast Parallel-IO. Well at least to a point where I don't know how to carry on...
First of all what I am trying to accomplish:
I need to control a set of actuators that have a 16bit parallel-bus-type interface. The actuators are daisy-chained on a 16bit interface with an extra set-pulse input. On each pulse on the set-line, the last 16-bit input is pulsed to the next actuator and so on. So what I need to do is provide 16-bit values one after the other on a GPIO from an array and as soon as they are present on the IO-pins, generate a puls on a separate IO-pin. The problem is, that the 16-bit words need to be supplied with 1 MHz and the controller needs to do computations and handling of serial interfaces on the side.
My idea so far was to use the pwm module with timer 1 to generate a 1MHz square wave aka the the update pulse and use the timer overflow DMA-request to automatically copy the next 16bit word from an array to the GPIOF output data register.
The hopefully relevant code snippets so far:
Code: Select all
#define STM32_TIM_CR2_CCDS (1U << 3)
// PWM configuration Timer1
static PWMConfig pwmcfg2 = {
1000, /* PWM clock frequency */
100, /* PWM period */
NULL, /* No callback */
{
{PWM_OUTPUT_DISABLED, NULL},
{PWM_OUTPUT_DISABLED, NULL},
{PWM_OUTPUT_DISABLED, NULL},
{PWM_OUTPUT_ACTIVE_HIGH, NULL},
},
0, /* CR2 register initialization*/
#if STM32_PWM_USE_ADVANCED
0, /* TIM BDTR (break & dead-time) register initialization */
#endif
STM32_TIM_DIER_UDE /* TIM DIER register initialization */
};
int main(void) {
uint16_t pattern[] = {0x000C,0x000C,0x000C};
halInit();
chSysInit();
pwmStart(&PWMD1, &pwmcfg2);
PWMD1.tim->CR2 |= STM32_TIM_CR2_CCDS;
pwmEnableChannel(&PWMD1, 3, 30);
// Allocate the stream
if (dmaStreamAllocate( STM32_DMA2_STREAM5, 0, NULL, NULL ))
chSysHalt();
// Set the source Address
dmaStreamSetPeripheral( STM32_DMA2_STREAM5, pattern );
// Set the destination address
dmaStreamSetMemory0( STM32_DMA2_STREAM5, GPIOF->ODR );
// set the size of the output buffer
dmaStreamSetTransactionSize( STM32_DMA2_STREAM5, 1 );
// config 16-bit HWORD transfers, memory to peripheral,
// inc source address, fixed dest address
dmaStreamSetMode( STM32_DMA2_STREAM5,
STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD |
STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2P |
STM32_DMA_CR_PINC | STM32_DMA_CR_CIRC |
STM32_DMA_CR_CHSEL(6));
dmaStreamSetFIFO(STM32_DMA2_STREAM5, 0);
dmaStreamEnable(STM32_DMA2_STREAM5);
while (TRUE) {
chThdSleepMilliseconds(500);
}
}
The timer itself is working and is generating the expected PWM output on the channel3 pin. GPIOF is setup as pushpull output and works OK when toggling with palTogglePad().
I don't know where or how to start debugging the DMA controller. I have already studied previous posts on the topic ( http://forum.chibios.org/phpbb/viewtopic.php?f=16&t=1669 http://forum.chibios.org/phpbb/viewtopic.php?f=8&t=1648, but I could not get the code snippets to work with the PWM module. I have also tried the GPT-module, but I can't get the Interrupt for the callback function to stop. At 1MHz interrupt rate, the controller stops working.
I hope that I could explain the prblem clearly and that someone can help.
Best regards,
Kai