Здравствуйте! Прошу консультации по следующей задаче. Имеется МК К1921ВК01Т, на нем я задействую 21 (из 24) первых каналов АЦП для измерения. Измерения запускаются постоянно по событию ШИМ, когда счетчик досчитывает до 0. Хочу сделать так, чтобы по окончании измерений запускался DMA, аккуратно складывал в структурку 21 результат измерения, и вызывал прерывания, в котором я что-то с ними делаю, и после DMA был опять готов к следующему периоду ШИМ. Таким образом я бы получал 21 свежее измерение на каждом периоде. Как я пытаюсь это сделать:
1. Инициализация ШИМ
- | Показать
-
Код: Выделить всё
NT_PWM0->TZCLR = 0x7;
NT_PWM0->TZINTCLR_bit.TZINT = 1;
NT_PWM0->TBPHS_bit.TBPHS = 0x0000;
NT_PWM0->TBPRD = PERIOD;
NT_PWM0->TBCTR = 0x0000;
NT_PWM0->TBCTL_bit.CTRMODE = 0x2;
NT_PWM0->TBCTL_bit.CLKDIV = 0;
NT_PWM0->TBCTL_bit.HSPCLKDIV = 0;
NT_PWM0->CMPCTL_bit.SHDWAMODE = 0;
NT_PWM0->CMPCTL_bit.LOADAMODE = 0;
NT_PWM0->CMPA_bit.CMPA = 0x0;
NT_PWM0->AQCTLA = 0;
NT_PWM0->AQCTLA_bit.CAD = 0b01;
NT_PWM0->AQCTLA_bit.CAU = 0b10;
NT_PWM0->AQSFRC_bit.RLDCSF = 0b00;
NT_PWM0->DBCTL_bit.IN_MODE = 0b00;
NT_PWM0->DBCTL_bit.POLSEL = 0b00;
NT_PWM0->DBCTL_bit.OUT_MODE = 0b00;
NT_PWM0->DBRED = 0;
NT_PWM0->DBFED = 0;
NT_PWM0->TZSEL_bit.OSHT0 = 0;
NT_PWM0->TZSEL_bit.OSHT1 = 0;
NT_PWM0->TZSEL_bit.OSHT2 = 0;
NT_PWM0->TZSEL_bit.OSHT3 = 0;
NT_PWM0->TZSEL_bit.OSHT4 = 0;
NT_PWM0->TZSEL_bit.OSHT5 = 0;
NT_PWM0->ETSEL_bit.SOCAEN = 1;
NT_PWM0->ETSEL_bit.SOCASEL = 1;
NT_PWM0->ETPS_bit.SOCAPRD = 0;
NT_PWM0->TZCTL_bit.TZA = 1;
2. Инициализация прерываний
- | Показать
Код: Выделить всё
void irq_ini(void)
{
DINT;
extern int *g_pfnVectors;
SCB->VTOR = (uint32_t) (&g_pfnVectors);
Энвик_SetPriorityGrouping(4);
Энвик_DisableIRQ(DMA_Stream10_IRQn);
Энвик_DisableIRQ(TIM1_IRQn);
Энвик_DisableIRQ(TIM0_IRQn);
Энвик_ClearPendingIRQ(DMA_Stream10_IRQn);
Энвик_ClearPendingIRQ(TIM1_IRQn);
Энвик_ClearPendingIRQ(TIM0_IRQn);
Энвик_EnableIRQ(DMA_Stream10_IRQn);
Энвик_SetPriority(DMA_Stream10_IRQn, 1);
Энвик_EnableIRQ(TIM1_IRQn);
Энвик_SetPriority(TIM1_IRQn, 4);
Энвик_EnableIRQ(TIM0_IRQn);
Энвик_SetPriority(TIM0_IRQn, 2);
}
3. Инициализация АЦП, использую один секвенсор 2 для запуска всех измерений
- | Показать
Код: Выделить всё
void adc_ini(void)
{
for (uint32_t i = 0; i < 24; i++) {
NT_ADC->DCCTL_bit[i].CHNL = 0x1F;
}
NT_ADC->ACTSS = 0; //sequencers are turned off
NT_ADC->SEQ[2].OP = 0; //number of sequencer module in brackets
NT_ADC->PP_bit[0].OM = 0x3; //number of adc module in brackets
NT_ADC->PP_bit[1].OM = 0x3;
NT_ADC->PP_bit[2].OM = 0x3;
NT_ADC->PP_bit[3].OM = 0x3;
NT_ADC->PP_bit[4].OM = 0x3;
NT_ADC->PP_bit[5].OM = 0x3;
NT_ADC->PP_bit[6].OM = 0x3;
NT_ADC->PP_bit[7].OM = 0x3;
NT_ADC->PP_bit[8].OM = 0x3;
NT_ADC->PP_bit[9].OM = 0x3;
NT_ADC->PP_bit[10].OM = 0x3;
NT_ADC->PP_bit[11].OM = 0x3;
NT_ADC->PP_bit[0].ENA = 1;
NT_ADC->PP_bit[1].ENA = 1;
NT_ADC->PP_bit[2].ENA = 1;
NT_ADC->PP_bit[3].ENA = 1;
NT_ADC->PP_bit[4].ENA = 1;
NT_ADC->PP_bit[5].ENA = 1;
NT_ADC->PP_bit[6].ENA = 1;
NT_ADC->PP_bit[7].ENA = 1;
NT_ADC->PP_bit[8].ENA = 1;
NT_ADC->PP_bit[9].ENA = 1;
NT_ADC->PP_bit[10].ENA = 1;
NT_ADC->PP_bit[11].ENA = 1;
NT_ADC->EMUX_bit.EM2 = 0x6; //6; //launch by PWM0 event
NT_ADC->SEQ[2].MUX_bit.CH0 = 1; //channels which are launched
NT_ADC->SEQ[2].MUX_bit.CH1 = 1;
NT_ADC->SEQ[2].MUX_bit.CH2 = 1;
NT_ADC->SEQ[2].MUX_bit.CH3 = 1;
NT_ADC->SEQ[2].MUX_bit.CH4 = 1;
NT_ADC->SEQ[2].MUX_bit.CH5 = 1;
NT_ADC->SEQ[2].MUX_bit.CH6 = 1;
NT_ADC->SEQ[2].MUX_bit.CH7 = 1;
NT_ADC->SEQ[2].MUX_bit.CH8 = 1;
NT_ADC->SEQ[2].MUX_bit.CH9 = 1;
NT_ADC->SEQ[2].MUX_bit.CH10 = 1;
NT_ADC->SEQ[2].MUX_bit.CH11 = 1;
NT_ADC->SEQ[2].MUX_bit.CH12 = 1;
NT_ADC->SEQ[2].MUX_bit.CH13 = 1;
NT_ADC->SEQ[2].MUX_bit.CH14 = 1;
NT_ADC->SEQ[2].MUX_bit.CH15 = 1;
NT_ADC->SEQ[2].MUX_bit.CH16 = 1;
NT_ADC->SEQ[2].MUX_bit.CH17 = 1;
NT_ADC->SEQ[2].MUX_bit.CH18 = 1;
NT_ADC->SEQ[2].MUX_bit.CH19 = 1;
NT_ADC->SEQ[2].MUX_bit.CH20 = 1;
NT_ADC->SEQ[2].CTL_bit.DMAEN = 1; //dma enabled
NT_ADC->SEQ[2].CTL_bit.WMARK = 0b110; //32 measurements
NT_ADC->SEQ[2].CTL_bit.ICNT = 0; //no interrupts
NT_ADC->IM_bit.MASK2 = 0;
NT_ADC->ACTSS_bit.ASEN2 = 1; //one of sequencers is on
NT_ADC->PSSI_bit.SS2 = 1;
}
4. Инициализация DMA
- | Показать
Код: Выделить всё
void dma_ini() {
// Инцииализация DMA
// Базовый указатель
DMA_BasePtrConfig((uint32_t)(&DMA_CONFIGDATA));
// Инициализация каналов
DMA_ChannelInit_TypeDef DMA_ChannelInitStruct;
DMA_ChannelStructInit(&DMA_ChannelInitStruct);
DMA_ChannelInitStruct.DMA_SrcDataSize = DMA_DataSize_32;
DMA_ChannelInitStruct.DMA_DstDataSize = DMA_DataSize_32;
DMA_ChannelInitStruct.DMA_ArbitrationRate = DMA_ArbitrationRate_1;
DMA_ChannelInitStruct.DMA_Mode = DMA_Mode_Basic;
DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_Disable;
DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_32;
// DMA10 - SEQ2
DMA_ChannelInitStruct.DMA_TransfersTotal = 21;// ADC_MEASURE_TOTAL;
DMA_ChannelInitStruct.DMA_SrcDataEndPtr = (uint32_t *)(&NT_ADC->SEQ[2].FIFO);
DMA_ChannelInitStruct.DMA_DstDataEndPtr = (uint32_t *) &adc.a1; //адрес первого элемента в структуре (в которой 21 элемент)
DMA_ChannelInit(&DMA_CONFIGDATA.PRM_DATA.CH[10], &DMA_ChannelInitStruct);
// Инциализация контроллера DMA
DMA_Init_TypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_Channel = DMA_Channel_ADCSEQ2;
DMA_InitStruct.DMA_ChannelEnable = ENABLE;
DMA_Init(&DMA_InitStruct);
DMA_MasterEnableCmd(ENABLE);
}
5. Прерывание
- | Показать
Код: Выделить всё
void DMA1_Stream10_IRQHandler(void)
{
// some actions
DMA_CONFIGDATA.PRM_DATA.CH[10].CHANNEL_CFG_bit.N_MINUS_1 = 21-1;
DMA_CONFIGDATA.PRM_DATA.CH[10].CHANNEL_CFG_bit.CYCLE_CTRL = DMA_Mode_Basic;
NT_DMA->CHNL_ENABLE_SET = DMA_Channel_ADCSEQ2;
}
Похожий вопрос был в основной теме про эти контроллеры, собственно оттуда я код для прерывания dma и взял. Но там примера кода не было, и это не помогло. Возможно ли так сделать, и если да, где мой косяк? В каком порядке измерения записываются в память (напр. структуру)? Заранее спасибо!