Open 14droplets opened 7 years ago
Улучшенная версия
#include <stm32f10x_conf.h>
#define BUFFER_SIZE (1280*5)
#define DMA_KICK_PERIOD (10)
uint8_t _buffer[BUFFER_SIZE] = {0x00};
void setup_timers()
{
// НАСТРОЙКА ТАЙМЕРА 2 (тот, который пинает DMA)
// ===============================================================
// ===============================================================
// ===============================================================
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// настраиваем таймер для генерации выводной частоты
TIM_TimeBaseInitTypeDef tim;
TIM_TimeBaseStructInit(&tim);
tim.TIM_Prescaler = 0x0000;
tim.TIM_CounterMode = TIM_CounterMode_Up;
tim.TIM_Period = DMA_KICK_PERIOD;
tim.TIM_ClockDivision = TIM_CKD_DIV1;
// tim.TIM_RepetitionCounter не используется на нашем таймере
TIM_TimeBaseInit(TIM2, &tim);
// настраиваем PWM, чтобы формировать выходной клок
// Используем третий канал, так как он позволяет расталкивать DMA по его первому каналу
TIM_OCInitTypeDef tim_oc;
TIM_OCStructInit(&tim_oc);
tim_oc.TIM_OCMode = TIM_OCMode_PWM2; // FIXME: Почему pwm1?
tim_oc.TIM_OutputState = TIM_OutputState_Enable; // включаем вывод на пин
//tim_pwm.TIM_OCNIdleState // только для таймеров 1, 8
tim_oc.TIM_Pulse = DMA_KICK_PERIOD / 2;
tim_oc.TIM_OCPolarity = TIM_OCPolarity_High; // FIXME: Тут нужно подумать
//tim_pwm.TIM_OCNPolarity; // только для таймеров 1, 8
//tim_pwm.TIM_OCIdleState; // только для таймеров 1, 8
//tim_pwm.TIM_OCNIdleState; // только для таймеров 1, 8
TIM_OC3Init(TIM2, &tim_oc);
// разрешаем таймеру обращаться к этому каналу DMA по событию совпадения счетчика с 3им CCR регистром
// для прогона одного байта через DMA
TIM_DMAConfig(TIM2, TIM_DMABase_CCR3, TIM_DMABurstLength_1Byte);
TIM_DMACmd(TIM2, TIM_DMA_CC3, ENABLE);
// РАзрешаем этому таймеру управлять ведомыми таймерами
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
// Выдаем им сигнал UPDATE
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
// Включаем для этого таймепра входной триггер с таймера 3
TIM_SelectInputTrigger(TIM2, TIM_TS_ITR2);
// Разрешаем другим таймерам управлять нашим клоком режимом гейтирования
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Gated);
// НАСТРОЙКА ТАЙМЕРА 3 (тот, который выключает таймер 2)
// ===============================================================
// ===============================================================
// ===============================================================
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//настраиваем таймер для отсчета количества прерываний таймера 2
TIM_TimeBaseInitTypeDef tim_cnt;
TIM_TimeBaseStructInit(&tim_cnt);
tim_cnt.TIM_Prescaler = 0x0000;
tim_cnt.TIM_CounterMode = TIM_CounterMode_Up;
tim_cnt.TIM_Period = 0xFFFF-1; // ведем таймер до максимума
tim_cnt.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &tim_cnt);
// настраиваем PWM, чтобы формировать выходной клок
TIM_OCStructInit(&tim_oc);
tim_oc.TIM_OCMode = TIM_OCMode_PWM1;
tim_oc.TIM_OutputState = TIM_OutputState_Disable;//TIM_OutputState_Enable;
//tim_pwm.TIM_OCNIdleState // только для таймеров 1, 8
tim_oc.TIM_Pulse = BUFFER_SIZE; // значение в CCR регистре
tim_oc.TIM_OCPolarity = TIM_OCPolarity_High; // FIXME: Тут нужно подумать
//tim_pwm.TIM_OCNPolarity; // только для таймеров 1, 8
//tim_pwm.TIM_OCIdleState; // только для таймеров 1, 8
//tim_pwm.TIM_OCNIdleState; // только для таймеров 1, 8
TIM_OC1Init(TIM3, &tim_oc);
// Разрешаем ему управлять ведомыми таймерами
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
// Передаем им наш сигнал с CCR1
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_OC1Ref);
// Будем слушать его клоки и тикать
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_External1);
// Сами будем использовать сигнал с таймера 2
TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);
// Настройка DMA
// настраиваем DMA для чтения данных по клоку, генерируемому таймером
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef dma;
dma.DMA_PeripheralBaseAddr = (uint32_t)&GPIOA->IDR;
dma.DMA_MemoryBaseAddr = (uint32_t)_buffer;
dma.DMA_DIR = DMA_DIR_PeripheralSRC;
dma.DMA_BufferSize = sizeof(_buffer);
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma.DMA_Mode = DMA_Mode_Normal;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_M2M = DMA_M2M_Disable;
// Настраиваем первый канал DMA и включаем его
DMA_Init(DMA1_Channel1, &dma);
DMA_Cmd(DMA1_Channel1, ENABLE);
// FIXME: для отладки - включаем прерывание по завершению прогона блока с DMA
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
NVIC_InitTypeDef dma_nvic;
dma_nvic.NVIC_IRQChannel = DMA1_Channel1_IRQn;
dma_nvic.NVIC_IRQChannelPreemptionPriority = 0;
dma_nvic.NVIC_IRQChannelSubPriority = 0;
dma_nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&dma_nvic);
}
int main(int argc, char* argv[])
{
setup_timers();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// TIM 2
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);
GPIO_InitTypeDef p;
p.GPIO_Mode = GPIO_Mode_AF_OD;
p.GPIO_Pin = GPIO_Pin_10;
p.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &p);
// PORTA
p.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;
p.GPIO_Mode = GPIO_Mode_IN_FLOATING;
p.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &p);
TIM_Cmd(TIM3, ENABLE);
TIM_Cmd(TIM2, ENABLE);
volatile int x = 0;
while(1)
{}
while(1)
{
TIM_Cmd(TIM2, DISABLE);
TIM_Cmd(TIM3, DISABLE);
TIM_GenerateEvent(TIM2, TIM_EventSource_Update);
TIM_GenerateEvent(TIM3, TIM_EventSource_Update);
while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET)
{}
DMA_DeInit(DMA1_Channel1);
TIM_Cmd(TIM3, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}
}
void DMA1_Channel1_IRQHandler()
{
volatile int x = 0;
}