АЦП + DMA К1921ВК01Т

32-разрядные микроконтроллеры разработки АО "НИИЭТ"

Модераторы: ea, dav, bkolbov, Alis, pip, _sva_

rasulikv
Сообщения: 6
Зарегистрирован: 15 янв 2018, 15:38
Предприятие: КВ-Системы

АЦП + DMA К1921ВК01Т

Сообщение rasulikv »

Здравствуйте! Прошу консультации по следующей задаче. Имеется МК К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 и взял. Но там примера кода не было, и это не помогло. Возможно ли так сделать, и если да, где мой косяк? В каком порядке измерения записываются в память (напр. структуру)? Заранее спасибо!
rasulikv
Сообщения: 6
Зарегистрирован: 15 янв 2018, 15:38
Предприятие: КВ-Системы

Re: АЦП + DMA К1921ВК01Т

Сообщение rasulikv »

Если уточнить проблему, то при такой настройке у меня даже в прерывание не заходит, если же поставить 16 измерений и 16 передач по dma, то прерывание вызывается корректно с нужной периодичностью (хотя корректность значений, записанных в структуру, я не проверял еще). Но как быть, если измерений 21, что меньше следующей настройки в 32 передачи?
Аватара пользователя
Лашкевич
Сообщения: 373
Зарегистрирован: 13 май 2015, 13:10
Предприятие: ООО "НПФ Вектор"
Откуда: Москва
Контактная информация:

Re: АЦП + DMA К1921ВК01Т

Сообщение Лашкевич »

А для чего тут DMA? Забирайте данные каждый период ШИМ прямо из NT_ADC->DCVAL_bit[номер канала].VAL . Или вы хотите прерывания реже? Тогда можно использовать встроенные fifo секвенсора, туда складывать данные, и забирать из NT_ADC->SEQ[номер_секвенсора].FIFO_bit.DATA; Правда, количество секвенсоров ограничено.
С уважением,
Лашкевич Максим.
Инженер-программист ООО "НПФ Вектор", Москва.
http://motorcontrol.ru/
rasulikv
Сообщения: 6
Зарегистрирован: 15 янв 2018, 15:38
Предприятие: КВ-Системы

Re: АЦП + DMA К1921ВК01Т

Сообщение rasulikv »

Спасибо за ответ! И верно, я так до этого и делал, но почему то мне казалось, что компараторов 12, по одному на каждое АЦП, и мне на всё не хватит, нужно городить DMA. А их на самом деле 24, и собственно проблемы 21 значение забрать за раз нет. С фифо как-то возиться не хотелось, из регистров удобнее забирать.
prostoRoman
Сообщения: 57
Зарегистрирован: 11 июл 2014, 15:06

Re: АЦП + DMA К1921ВК01Т

Сообщение prostoRoman »

А вопрос с ДМА так и остался.
Получается, если поменять цифру 16 на цифру 21 ДМА перестаёт работать? С какими ещё цифрами ДМА не будет работать? Может их все перечислить в документации?

Ещё. Почему пропадает прерывание не понятно, но вот строка, вызывающая у меня вопрос:

Код: Выделить всё

DMA_ChannelInitStruct.DMA_DstDataEndPtr = (uint32_t *) &adc.a1; //адрес первого элемента в структуре (в которой 21 элемент)
а1 - это ПОСЛЕДНИЙ элемент в массиве из 21 элемента?
Ведь DMA_DstDataEndPtr - это указатель на последний элемент в массиве назначения. Предполагаю в таком случае по данным о работе передаче судить будет нельзя.
dav
Сообщения: 209
Зарегистрирован: 14 дек 2015, 09:21
Предприятие: АО НИИЭТ
Откуда: АО НИИЭТ, Воронеж

Re: АЦП + DMA К1921ВК01Т

Сообщение dav »

В таблице А.1.12 на стр. 229 Руководства пользователя К1921ВК01Т перечислены все допустимые значения количества результатов измерений записанных в буфер секвенсора, по достижению которого вызывается DMA:
Вложения
K1921VK01T_Field_WMARK.JPG
K1921VK01T_Field_WMARK.JPG (29.94 КБ) 2444 просмотра
rasulikv
Сообщения: 6
Зарегистрирован: 15 янв 2018, 15:38
Предприятие: КВ-Системы

Re: АЦП + DMA К1921ВК01Т

Сообщение rasulikv »

prostoRoman писал(а): 03 июн 2020, 14:49 А вопрос с ДМА так и остался.
Получается, если поменять цифру 16 на цифру 21 ДМА перестаёт работать? С какими ещё цифрами ДМА не будет работать? Может их все перечислить в документации?

Ещё. Почему пропадает прерывание не понятно, но вот строка, вызывающая у меня вопрос:

Код: Выделить всё

DMA_ChannelInitStruct.DMA_DstDataEndPtr = (uint32_t *) &adc.a1; //адрес первого элемента в структуре (в которой 21 элемент)
а1 - это ПОСЛЕДНИЙ элемент в массиве из 21 элемента?
Ведь DMA_DstDataEndPtr - это указатель на последний элемент в массиве назначения. Предполагаю в таком случае по данным о работе передаче судить будет нельзя.
Да, вы правы, нужно ставить указатель на конец массива, но думаю прерывание не по этой причине пропадало. Если бы я начал потом проверять, что туда пишется, я бы этот косяк нашел и исправил. А по поводу DMA - судя по доке, действительно можно отправлять только 2^n значений до 32, с промежуточными значениями не будет работать, для моего случая не очень удобно.
prostoRoman
Сообщения: 57
Зарегистрирован: 11 июл 2014, 15:06

Re: АЦП + DMA К1921ВК01Т

Сообщение prostoRoman »

Исходя из вышесказанного я вижу такое решение: секвенсор формирует запрос в ДМА каждое измерение, ДМА делает 21 транзакцию по 1, после чего формирует прерывание ядру.

Если всё так, то в принципе не корректно было настроено изначально - на 21(32) преобразования ДМА выполнял бы одну транзакцию в одно слово (если сигнал запроса транзакции сбрасывается первым чтением, а не вычитыванием буфера до пустого).

Попробуйте, интересно =)
__Max__
Сообщения: 10
Зарегистрирован: 01 ноя 2022, 22:49
Предприятие: Cyberdyne Systems

Re: АЦП + DMA К1921ВК01Т

Сообщение __Max__ »

prostoRoman писал(а): 03 июн 2020, 22:56 Исходя из вышесказанного я вижу такое решение: секвенсор формирует запрос в ДМА каждое измерение, ДМА делает 21 транзакцию по 1, после чего формирует прерывание ядру.

Если всё так, то в принципе не корректно было настроено изначально - на 21(32) преобразования ДМА выполнял бы одну транзакцию в одно слово (если сигнал запроса транзакции сбрасывается первым чтением, а не вычитыванием буфера до пустого).

Попробуйте, интересно =)
Действительно..., вопрос к разработчикам, наличие цифры, кратной двойке означает, что АЦП формирует запрос dma_req на блочную передачу DMA или же запрос dma_sreq на одиночную передачу DMA тоже заведен от АЦП к DMA ??
__Max__
Сообщения: 10
Зарегистрирован: 01 ноя 2022, 22:49
Предприятие: Cyberdyne Systems

Re: АЦП + DMA К1921ВК01Т

Сообщение __Max__ »

Сам спросил, сам отвечу))) ...цитата из руководства "Контроллер DMA имеет возможность обслуживать сигналы запроса на одиночный
обмен SREQ и запроса на пакетный обмен BREQ блоков UART, SPI. Блок ADC генерирует
только запросы на пакетный обмен BREQ."
Тогда как осуществляется передача одного значения из буфера АЦП через DMA ?)
Ответить

Вернуться в «32-разрядные микроконтроллеры»