Страница 1 из 2

Работа с АЦП

Добавлено: 04 фев 2021, 16:47
Amelin!
С МК 1921ВК01Т работаем впервые, разбираемся с работой на основе проекта MCD.
Одной из задач является считывание значений трех токов двигателя, управляемого ШИМом.
Пытались для нашей программы использовать модуль V_adc проекта MCD, но опыта не хватает.
Хотелось бы получить более подробное описание механизма инициализации и работы модуля
или пример минимальной программы с модулем V_adc

Re: Работа с АЦП

Добавлено: 04 фев 2021, 18:41
Лашкевич Максим
Добрый день. Ну надо лабораторные работы поделать, подавать на АЦП что-то, смотреть что измеряется, читать ТО.
Вот тут есть примеры от производителя попроще
https://bitbucket.org/niietcm4/k1921vkx ... m4_pd/adc/

Если не хотите использовать фифо, можно считывать данные напрямую с регистров АЦП, результаты попадают в регистры компаратора:

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

myvalue = NT_ADC->DCVAL_bit[0].VAL;

Re: Работа с АЦП

Добавлено: 05 фев 2021, 14:43
Amelin!
Прилагаю проект сделанный на основе примеров,
значения приходят одни и те же, не зависимо от сигнала на входе АЦП, переменная res, см снимок
Просьба помочь с поиском ошибок в работе с АЦП.
Есть ли возможность отслеживать значения переменных в режиме Run в среду отладки.



#include "DSP.h"
#include "main.h"
#include <string.h> //для memcpy
#include "PWM_macros.h"

#define iStart NT_GPIOA->DATA & (1 << 3) //A3 Старт
#define iOpen NT_GPIOC->DATA & (1 << 0) //C0
#define iClose NT_GPIOC->DATA & (1 << 1) //C1


#define iHollA NT_GPIOH->DATA & (1 << 4)) //H4 Холл А
#define iHollB NT_GPIOH->DATA & (1 << 3)) //H3 Холл В
#define iHollC NT_GPIOH->DATA & (1 << 5)) //H5 Холл С

#define MGN_OFF NT_GPIOG->MASKHIGHBYTE_bit[2].MASKHB = 0
#define MGN_ON NT_GPIOG->MASKHIGHBYTE_bit[2].MASKHB = 2


int MotorStep = 0;
int HallCurr = 0;
int HallPrew = 0;
volatile uint32_t adc_irq_flag = 0;
int PrewA = 0;
int PrewB = 0;
int PrewC = 0;

int i=0;
int tmpHall=0;
int HallMode = 0;

int32 OffTime = 500; // 100 - 10ms 500 - 50ms
int BaseClokc = 10000;
int TiON = 0;
int TiOFF = 0;
int Step = 0;
int StartTiOFF = 0;

int32 StepPWM = 1;
int32 CurrPWM = 0;

int START = 0;
int TimerPeriod = 1000;

int tmp = 0;

// инициализации дискретных входов/выходов
void DIO_init (void)
{
// дискретные входы
NT_GPIOA->ALTFUNCCLR = (1 << 3);
NT_GPIOC->ALTFUNCCLR = (1 << 0) | (1 << 1); //выключить альт. функцию
NT_GPIOH->ALTFUNCCLR = (1 << 3) | (1 << 4) | (1 << 5); //выключить альт. функцию

NT_GPIOA->OUTENCLR = (1 << 3); //вход
NT_GPIOC->OUTENCLR = (1 << 0) | (1 << 1); //вход
NT_GPIOH->OUTENCLR = (1 << 3) | (1 << 4) | (1 << 5); //вход


//выход
NT_GPIOD->ALTFUNCCLR_bit.ALTFUNCCLR = (1 << 0); //RS power
NT_GPIOD->OUTENSET_bit.OUTENSET |= (1 << 0);

NT_GPIOG->ALTFUNCCLR_bit.ALTFUNCCLR = (1 << 10);// magnit
NT_GPIOG->OUTENSET_bit.OUTENSET |= (1 << 10);



TiON = BaseClokc * 0.01; //0.01 c = 10 мс
TiOFF = BaseClokc * 0.01; //0.01 c = 10 мс
Step = 1; //0.01 c = 10 мс

}


void myPWM_7()
{
NT_PWM7->TBPRD = 1000; //Период счета таймера - 10000, что соответствует частоте ШИМ 5 кГц при счете вверх-вниз
NT_PWM7->TBPHS_bit.TBPHS = 0x0000; //Фазовый сдвиг - 0
NT_PWM7->TBCTR = 0x0000; //Очищаем счетчик таймера

NT_PWM7->TBCTL_bit.PRDLD = TB_SHADOW; //Загрузка периода в TBPRD при TBCTR = 0
NT_PWM7->TBCTL_bit.CTRMODE = TB_COUNT_UPDOWN; //Режим счета - вверх-вниз
NT_PWM7->TBCTL_bit.PHSEN = TB_DISABLE; //Запрещена загрузка счетчика TBCTR значением регистра фазы TBPHS при получении события синхронизации
NT_PWM7->TBCTL_bit.HSPCLKDIV = 1; //Второй делитель тактовой частоты - 1
NT_PWM7->TBCTL_bit.CLKDIV = 1; //Первый делитель тактовой частоты - 1
NT_PWM7->TBCTL_bit.SYNCOSEL = TB_CTR_ZERO; //Выдаём синхро-сигнал при TBCTR = 0

NT_PWM7->CMPCTL_bit.SHDWAMODE = CC_SHADOW; //Включить SHADOW для сравнения (загрузка уставки сравнения через теневой регистр)
NT_PWM7->CMPCTL_bit.LOADAMODE = CC_CTR_ZERO; //Загрузка уставки сравнения по нулю счетчика
NT_PWM7->CMPCTL_bit.SHDWBMODE = CC_SHADOW; //Включить SHADOW для сравнения (загрузка уставки сравнения через теневой регистр)
NT_PWM7->CMPCTL_bit.LOADBMODE = CC_CTR_ZERO; //Загрузка уставки сравнения по нулю счетчика

NT_PWM7->CMPA_bit.CMPA = 0; //Уставка сравнения

NT_PWM7->AQCTLA = 0; //Для начала события для PWMA запрещены
NT_PWM7->AQCTLA_bit.ZRO = 1; //Обнуляем выход при нуле счетчика
NT_PWM7->AQCTLA_bit.CAU = 2; //Включаем выход при сравнении на возрастающей ветви счета (когда счеткик считает вверх)
NT_PWM7->AQCTLA_bit.CAD = 1; //Обнуляем выход при сравнении на спадающей ветви счета

NT_PWM7->DBRED = 0;
NT_PWM7->DBFED = NT_PWM7->DBRED;
NT_PWM7->DBCTL_bit.IN_MODE = DBA_RED_DBB_FED; //Сигнал PWMA используется для контроля по переднему фронту, а сигнал PWMB – по заднему
NT_PWM7->DBCTL_bit.OUT_MODE = DB_FULL_ENABLE; //Задержка включена для переднего фронта PWMA и заднего фронта PWMB
NT_PWM7->DBCTL_bit.POLSEL = DB_ACTV_HI;// DB_ACTV_HIC; //Задание полярности сигнала на выходе: инверсия только на выводе PWMB

NT_PWM7->ETSEL_bit.INTSEL = ET_DISABLE; //Событие для прерывания модуля ШИМ не выбрано
NT_PWM7->ETSEL_bit.INTEN = 0; //Запретить прерывания модуля ШИМ

NT_PWM7->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//Запрещаем всем TZ быть источникоми аппаратной аварии (one-shot)
NT_PWM7->TZSEL_bit.OSHT0 = TZ_DISABLE;
NT_PWM7->TZSEL_bit.OSHT1 = TZ_DISABLE;
NT_PWM7->TZSEL_bit.OSHT2 = TZ_DISABLE;
NT_PWM7->TZSEL_bit.OSHT3 = TZ_DISABLE;
NT_PWM7->TZSEL_bit.OSHT4 = TZ_DISABLE;
NT_PWM7->TZSEL_bit.OSHT5 = TZ_DISABLE;

//Для PWMB тоже самое, что для PWMА. Без инверсии. Инверсия далее в модуле МВ
NT_PWM7->AQCTLB = NT_PWM7->AQCTLA; //Тоже самое
NT_PWM7->AQSFRC_bit.RLDCSF = 3; //Реагировать на программную привязку ног без теневого регистра

NT_PWM7->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//Запрещаем прерывание по аварии (one-shot)
NT_PWM7->TZEINT_bit.OST = 0;

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM7->TZCTL_bit.TZA = 0;
NT_PWM7->TZCTL_bit.TZB = 0;
}

void myPWM_0()
{

//Настроим модули ШИМ
//сбрасываем все флаги аварий TZ и их прерываний
NT_PWM0->TZCLR = 0x7;
NT_PWM0->TZINTCLR_bit.TZINT = 1;


NT_PWM0->TBPRD = 1000; //Период счета таймера - 10000, что соответствует частоте ШИМ 5 кГц при счете вверх-вниз
NT_PWM0->TBPHS_bit.TBPHS = 0x0000; //Фазовый сдвиг - 0
NT_PWM0->TBCTR = 0x0000; //Очищаем счетчик таймера
NT_PWM0->TBCTL = NT_PWM7->TBCTL;
NT_PWM0->CMPCTL = NT_PWM7->CMPCTL;

NT_PWM0->CMPA_bit.CMPA = 0; //Уставка сравнения

NT_PWM0->AQCTLA = NT_PWM7->AQCTLA; //Для начала события для PWMA запрещены

NT_PWM0->DBRED = 0;
NT_PWM0->DBFED = NT_PWM0->DBRED;
NT_PWM0->DBCTL = NT_PWM7->DBCTL;


NT_PWM0->ETSEL_bit.INTSEL = ET_DISABLE; //Событие для прерывания модуля ШИМ не выбрано
NT_PWM0->ETSEL_bit.INTEN = 0; //Запретить прерывания модуля ШИМ

NT_PWM0->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//Запрещаем всем TZ быть источникоми аппаратной аварии (one-shot)
NT_PWM0->TZSEL_bit.OSHT0 = TZ_DISABLE;
NT_PWM0->TZSEL_bit.OSHT1 = TZ_DISABLE;
NT_PWM0->TZSEL_bit.OSHT2 = TZ_DISABLE;
NT_PWM0->TZSEL_bit.OSHT3 = TZ_DISABLE;
NT_PWM0->TZSEL_bit.OSHT4 = TZ_DISABLE;
NT_PWM0->TZSEL_bit.OSHT5 = TZ_DISABLE;

//Запрещаем прерывание по аварии (one-shot)
NT_PWM0->TZEINT_bit.OST = 0;

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM0->TZCTL_bit.TZA = 0;
// NT_PWM7->TZCTL_bit.TZB = 0;

//Для PWMB тоже самое, что для PWMА. Без инверсии. Инверсия далее в модуле МВ
NT_PWM0->AQCTLB = NT_PWM0->AQCTLA; //Тоже самое
NT_PWM0->AQSFRC_bit.RLDCSF = 3; //Реагировать на программную привязку ног без теневого регистра

// DB_FULL_ENABLE; //Задержка включена для переднего фронта PWMA и заднего фронта PWMB
NT_PWM0->DBCTL_bit.POLSEL = DB_ACTV_HI;// DB_ACTV_HIC; //Задание полярности сигнала на выходе: инверсия только на выводе PWMB

NT_PWM0->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM0->TZCTL_bit.TZA = 0;
NT_PWM0->TZCTL_bit.TZB = 0;
}

void myPWM_1()
{
//Настроим модули ШИМ
//сбрасываем все флаги аварий TZ и их прерываний
NT_PWM1->TZCLR = 0x7;
NT_PWM1->TZINTCLR_bit.TZINT = 1;


NT_PWM1->TBPRD = 1000; //Период счета таймера - 10000, что соответствует частоте ШИМ 5 кГц при счете вверх-вниз
NT_PWM1->TBPHS_bit.TBPHS = 0x0000; //Фазовый сдвиг - 0
NT_PWM1->TBCTR = 0x0000; //Очищаем счетчик таймера
NT_PWM1->TBCTL = NT_PWM7->TBCTL;
NT_PWM1->CMPCTL = NT_PWM7->CMPCTL;

NT_PWM1->CMPA_bit.CMPA = 0; //Уставка сравнения

NT_PWM1->AQCTLA = NT_PWM7->AQCTLA; //Для начала события для PWMA запрещены

NT_PWM1->DBRED = 0;
NT_PWM1->DBFED = NT_PWM1->DBRED;
NT_PWM1->DBCTL = NT_PWM7->DBCTL;


NT_PWM1->ETSEL_bit.INTSEL = ET_DISABLE; //Событие для прерывания модуля ШИМ не выбрано
NT_PWM1->ETSEL_bit.INTEN = 0; //Запретить прерывания модуля ШИМ

NT_PWM1->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//Запрещаем всем TZ быть источникоми аппаратной аварии (one-shot)
NT_PWM1->TZSEL_bit.OSHT0 = TZ_DISABLE;
NT_PWM1->TZSEL_bit.OSHT1 = TZ_DISABLE;
NT_PWM1->TZSEL_bit.OSHT2 = TZ_DISABLE;
NT_PWM1->TZSEL_bit.OSHT3 = TZ_DISABLE;
NT_PWM1->TZSEL_bit.OSHT4 = TZ_DISABLE;
NT_PWM1->TZSEL_bit.OSHT5 = TZ_DISABLE;

//Запрещаем прерывание по аварии (one-shot)
NT_PWM1->TZEINT_bit.OST = 0;

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM1->TZCTL_bit.TZA = 0;
// NT_PWM7->TZCTL_bit.TZB = 0;

//Для PWMB тоже самое, что для PWMА. Без инверсии. Инверсия далее в модуле МВ
NT_PWM1->AQCTLB = NT_PWM1->AQCTLA; //Тоже самое
NT_PWM1->AQSFRC_bit.RLDCSF = 3; //Реагировать на программную привязку ног без теневого регистра

// DB_FULL_ENABLE; //Задержка включена для переднего фронта PWMA и заднего фронта PWMB
NT_PWM1->DBCTL_bit.POLSEL = DB_ACTV_HI;// DB_ACTV_HIC; //Задание полярности сигнала на выходе: инверсия только на выводе PWMB

NT_PWM1->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM1->TZCTL_bit.TZA = 0;
NT_PWM1->TZCTL_bit.TZB = 0;
}

void myPWM_2()
{
//Настроим модули ШИМ
//сбрасываем все флаги аварий TZ и их прерываний
NT_PWM2->TZCLR = 0x7;
NT_PWM2->TZINTCLR_bit.TZINT = 1;


NT_PWM2->TBPRD = 1000; //Период счета таймера - 10000, что соответствует частоте ШИМ 5 кГц при счете вверх-вниз
NT_PWM2->TBPHS_bit.TBPHS = 0x0000; //Фазовый сдвиг - 0
NT_PWM2->TBCTR = 0x0000; //Очищаем счетчик таймера
NT_PWM2->TBCTL = NT_PWM7->TBCTL;
NT_PWM2->CMPCTL = NT_PWM7->CMPCTL;

NT_PWM2->CMPA_bit.CMPA = 0; //Уставка сравнения

NT_PWM2->AQCTLA = NT_PWM7->AQCTLA; //Для начала события для PWMA запрещены

NT_PWM2->DBRED = 0;
NT_PWM2->DBFED = NT_PWM2->DBRED;
NT_PWM2->DBCTL = NT_PWM7->DBCTL;


NT_PWM2->ETSEL_bit.INTSEL = ET_DISABLE; //Событие для прерывания модуля ШИМ не выбрано
NT_PWM2->ETSEL_bit.INTEN = 0; //Запретить прерывания модуля ШИМ

NT_PWM2->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//Запрещаем всем TZ быть источникоми аппаратной аварии (one-shot)
NT_PWM2->TZSEL_bit.OSHT0 = TZ_DISABLE;
NT_PWM2->TZSEL_bit.OSHT1 = TZ_DISABLE;
NT_PWM2->TZSEL_bit.OSHT2 = TZ_DISABLE;
NT_PWM2->TZSEL_bit.OSHT3 = TZ_DISABLE;
NT_PWM2->TZSEL_bit.OSHT4 = TZ_DISABLE;
NT_PWM2->TZSEL_bit.OSHT5 = TZ_DISABLE;

//Запрещаем прерывание по аварии (one-shot)
NT_PWM2->TZEINT_bit.OST = 0;

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM2->TZCTL_bit.TZA = 0;
// NT_PWM7->TZCTL_bit.TZB = 0;

//Для PWMB тоже самое, что для PWMА. Без инверсии. Инверсия далее в модуле МВ
NT_PWM2->AQCTLB = NT_PWM2->AQCTLA; //Тоже самое
NT_PWM2->AQSFRC_bit.RLDCSF = 3; //Реагировать на программную привязку ног без теневого регистра

// DB_FULL_ENABLE; //Задержка включена для переднего фронта PWMA и заднего фронта PWMB
NT_PWM2->DBCTL_bit.POLSEL = DB_ACTV_HI;// DB_ACTV_HIC; //Задание полярности сигнала на выходе: инверсия только на выводе PWMB

NT_PWM2->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM2->TZCTL_bit.TZA = 0;
NT_PWM2->TZCTL_bit.TZB = 0;

}

void myPWM_6()
{

//Настроим модули ШИМ
//сбрасываем все флаги аварий TZ и их прерываний
NT_PWM6->TZCLR = 0x7;
NT_PWM6->TZINTCLR_bit.TZINT = 1;


NT_PWM6->TBPRD = 1000; //Период счета таймера - 10000, что соответствует частоте ШИМ 5 кГц при счете вверх-вниз
NT_PWM6->TBPHS_bit.TBPHS = 0x0000; //Фазовый сдвиг - 0
NT_PWM6->TBCTR = 0x0000; //Очищаем счетчик таймера
NT_PWM6->TBCTL = NT_PWM7->TBCTL;
NT_PWM6->CMPCTL = NT_PWM7->CMPCTL;

NT_PWM6->CMPA_bit.CMPA = 0; //Уставка сравнения

NT_PWM6->AQCTLA = NT_PWM7->AQCTLA; //Для начала события для PWMA запрещены

NT_PWM6->DBRED = 0;
NT_PWM6->DBFED = NT_PWM6->DBRED;
NT_PWM6->DBCTL = NT_PWM7->DBCTL;


NT_PWM6->ETSEL_bit.INTSEL = ET_DISABLE; //Событие для прерывания модуля ШИМ не выбрано
NT_PWM6->ETSEL_bit.INTEN = 0; //Запретить прерывания модуля ШИМ

NT_PWM6->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//Запрещаем всем TZ быть источникоми аппаратной аварии (one-shot)
NT_PWM6->TZSEL_bit.OSHT0 = TZ_DISABLE;
NT_PWM6->TZSEL_bit.OSHT1 = TZ_DISABLE;
NT_PWM6->TZSEL_bit.OSHT2 = TZ_DISABLE;
NT_PWM6->TZSEL_bit.OSHT3 = TZ_DISABLE;
NT_PWM6->TZSEL_bit.OSHT4 = TZ_DISABLE;
NT_PWM6->TZSEL_bit.OSHT5 = TZ_DISABLE;

//Запрещаем прерывание по аварии (one-shot)
NT_PWM6->TZEINT_bit.OST = 0;

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM6->TZCTL_bit.TZA = 0;
// NT_PWM7->TZCTL_bit.TZB = 0;

//Для PWMB тоже самое, что для PWMА. Без инверсии. Инверсия далее в модуле МВ
NT_PWM6->AQCTLB = NT_PWM6->AQCTLA; //Тоже самое
NT_PWM6->AQSFRC_bit.RLDCSF = 3; //Реагировать на программную привязку ног без теневого регистра

// DB_FULL_ENABLE; //Задержка включена для переднего фронта PWMA и заднего фронта PWMB
NT_PWM6->DBCTL_bit.POLSEL = DB_ACTV_HI;// DB_ACTV_HIC; //Задание полярности сигнала на выходе: инверсия только на выводе PWMB

NT_PWM6->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM6->TZCTL_bit.TZA = 0;
NT_PWM6->TZCTL_bit.TZB = 0;
}

void myPWM_8()
{
//Модуль PWM8
NT_PWM8->TBPRD = 1000; //Период счета таймера - 10000, что соответствует частоте ШИМ 5 кГц при счете вверх-вниз
NT_PWM8->TBPHS_bit.TBPHS = 0x0000; //Фазовый сдвиг - 0
NT_PWM8->TBCTR = 0x0000; //Очищаем счетчик таймера

NT_PWM8->TBCTL_bit.PRDLD = TB_SHADOW; //Загрузка периода в TBPRD при TBCTR = 0
NT_PWM8->TBCTL_bit.CTRMODE = TB_COUNT_UPDOWN; //Режим счета - вверх-вниз
NT_PWM8->TBCTL_bit.PHSEN = TB_DISABLE; //Запрещена загрузка счетчика TBCTR значением регистра фазы TBPHS при получении события синхронизации
NT_PWM8->TBCTL_bit.HSPCLKDIV = 1; //Второй делитель тактовой частоты - 1
NT_PWM8->TBCTL_bit.CLKDIV = 1; //Первый делитель тактовой частоты - 1
NT_PWM8->TBCTL_bit.SYNCOSEL = TB_CTR_ZERO; //Выдаём синхро-сигнал при TBCTR = 0

NT_PWM8->CMPCTL_bit.SHDWAMODE = CC_SHADOW; //Включить SHADOW для сравнения (загрузка уставки сравнения через теневой регистр)
NT_PWM8->CMPCTL_bit.LOADAMODE = CC_CTR_ZERO; //Загрузка уставки сравнения по нулю счетчика
NT_PWM8->CMPCTL_bit.SHDWBMODE = CC_SHADOW; //Включить SHADOW для сравнения (загрузка уставки сравнения через теневой регистр)
NT_PWM8->CMPCTL_bit.LOADBMODE = CC_CTR_ZERO; //Загрузка уставки сравнения по нулю счетчика

NT_PWM8->CMPA_bit.CMPA = 0; //Уставка сравнения

NT_PWM8->AQCTLA = 0; //Для начала события для PWMA запрещены
NT_PWM8->AQCTLA_bit.ZRO = 1; //Обнуляем выход при нуле счетчика
NT_PWM8->AQCTLA_bit.CAU = 2; //Включаем выход при сравнении на возрастающей ветви счета (когда счеткик считает вверх)
NT_PWM8->AQCTLA_bit.CAD = 1; //Обнуляем выход при сравнении на спадающей ветви счета

NT_PWM8->DBRED = 0;
NT_PWM8->DBFED = NT_PWM8->DBRED;
NT_PWM8->DBCTL_bit.IN_MODE = DBA_RED_DBB_FED; //Сигнал PWMA используется для контроля по переднему фронту, а сигнал PWMB – по заднему
NT_PWM8->DBCTL_bit.OUT_MODE = DB_FULL_ENABLE; //Задержка включена для переднего фронта PWMA и заднего фронта PWMB
NT_PWM8->DBCTL_bit.POLSEL = DB_ACTV_HI;// DB_ACTV_HIC; //Задание полярности сигнала на выходе: инверсия только на выводе PWMB

NT_PWM8->ETSEL_bit.INTSEL = ET_DISABLE; //Событие для прерывания модуля ШИМ не выбрано
NT_PWM8->ETSEL_bit.INTEN = 0; //Запретить прерывания модуля ШИМ

NT_PWM8->TBCTL_bit.FREE_SOFT = 0; //Остановка таймера сразу при остановке процессора

//*********************************************************************
//Запрещаем всем TZ быть источникоми аппаратной аварии (one-shot)
NT_PWM8->TZSEL_bit.OSHT0 = TZ_DISABLE;
NT_PWM8->TZSEL_bit.OSHT1 = TZ_DISABLE;
NT_PWM8->TZSEL_bit.OSHT2 = TZ_DISABLE;
NT_PWM8->TZSEL_bit.OSHT3 = TZ_DISABLE;
NT_PWM8->TZSEL_bit.OSHT4 = TZ_DISABLE;
NT_PWM8->TZSEL_bit.OSHT5 = TZ_DISABLE;

//Запрещаем прерывание по аварии (one-shot)
NT_PWM8->TZEINT_bit.OST = 0;

//При получении сигнала аппаратной аварии ШИМ-выходы переводятся в Z-состояние
NT_PWM8->TZCTL_bit.TZA = 0;
// NT_PWM7->TZCTL_bit.TZB = 0;
}
void PWM_init ()
{

//настроить в режиме ШИМ. Выполним настройку.
//1) Выбираем нужную альт. функцию (ШИМ-выход)
//2) Активируем альтернативную функцию

NT_COMMON_REG->GPIOPCTLB_bit.PIN5 = 2; //альт. функция - PWM_A7
NT_GPIOB->ALTFUNCSET_bit.ALTFUNCSET |= (1 << 5);

NT_COMMON_REG->GPIOPCTLA_bit.PIN4 = 1; //альт. функция - PWM_B6
NT_GPIOA->ALTFUNCSET_bit.ALTFUNCSET |= (1 << 4);

NT_COMMON_REG->GPIOPCTLA_bit.PIN7 = 1; //альт. функция - PWM_A8
NT_GPIOA->ALTFUNCSET_bit.ALTFUNCSET |= (1 << 7);


NT_COMMON_REG->GPIOPCTLA_bit.PIN10 = 2; //альт. функция - PWM_B0
NT_GPIOA->ALTFUNCSET_bit.ALTFUNCSET |= (1 << 10);

NT_COMMON_REG->GPIOPCTLA_bit.PIN11 = 2; //альт. функция - PWM_B1
NT_GPIOA->ALTFUNCSET_bit.ALTFUNCSET |= (1 << 11);

NT_COMMON_REG->GPIOPCTLA_bit.PIN12 = 2; //альт. функция - PWM_B2
NT_GPIOA->ALTFUNCSET_bit.ALTFUNCSET |= (1 << 12);

myPWM_7();

myPWM_0();
myPWM_1();
myPWM_2();
myPWM_6();

myPWM_8();


NT_COMMON_REG->PWM_SYNC_bit.TBCLKSYNC = 0x01FF; //синхронизация таймеров
}

void adc_init()
{
NT_COMMON_REG->APB_CLK_bit.ADCEN = 1;
// хак, чтобы избежать зависших секвенсоров от выставленных запросов по 0 каналу
// цифровыми компараторами. Хотя в данном случае это необязательно, т.к. 0-ой канал используется.
for (uint32_t i = 0; i < 24; i++) {
NT_ADC->DCCTL_bit.CHNL = 0x1F;
}

// NT_ADC->DCCTL_bit[0].CHNL = 0; //Ток фазы A


// включаем тактирование 0-модуля ацп (0 и 1 каналы)
// делим системную частоту на 8, и получаем тактирование АЦП 12,5МГц.
NT_COMMON_REG->ADC_CTRL0_bit.DIV_ADC0 = 3;
NT_COMMON_REG->ADC_CTRL0_bit.DIVEN_ADC0 = 1;
NT_COMMON_REG->ADC_CTRL0_bit.CLKEN_ADC0 = 1;

// настройка модуля АЦП0
NT_ADC->SAC_bit.AVG0 = 4; // avg 16
NT_ADC->PP_bit[0].OM = ((0 << 6) | // ch B
(1 << 4) | // diff on ch A (A-B)
(0 << 3) | // 12 bit
(3 << 0)); // modeactive
NT_ADC->PP_bit[0].ENA = 1; // включение модуля АЦП

// настройка секвенсора 0
NT_ADC->EMUX_bit.EM0 = 0xA; //старт по SOCA PWM 6, 7, 8
NT_ADC->SEQ[0].MUX = 1 << 0; // ch 0

// включаем прерывание секвенсора после каждого измерения
NT_ADC->SEQ[0].CTL_bit.ICNT = 0;
NT_ADC->IM_bit.MASK0 = 1;
NVIC_EnableIRQ(ADC_SEQ0_IRQn);
}

void Timer_and_interrupt_init (void)
{
volatile uint32_t priority;
volatile uint32_t priorityGroup;

extern int *g_pfnVectors;//Указатель на массив векторов прерываний, объявлен в startup_MCP_gcc.s
//Надо показать в регистре SCB->VTOR, где лежит таблица прерываний.
//А лежит она там, куда записал её линкер, в зависимости от файла компоновки.
//Поэтому берем адрес от массива g_pfnVectors и кладем туда
SCB->VTOR = (uint32_t)(&g_pfnVectors);//Sets the vector table location and Offset.

DINT; //запретить все прерывания

//Настраиваем группировку прерываний. Значение "4" означает, что будет использовано 8 групп и 2 подгруппы.
//Чем меньше номер группы или подгруппы, тем выше приоритет прерываний в ней.
//Прерывания по группам работают с "вытеснением", а по подгруппам - без "вытеснения".
//Пример. Если во время обработки прерывания группы 5 возник запрос на обработку прерывания группы 2, то
//начнется процедура обработки прерывания группы 2, а после его завершения процессор продолжит
//обработку прерывания группы 5. Если во время обработки прерывания ПОДгруппы 1 возник запрос на обработку
//прерывания ПОДгруппы 0 (внутри одной группы), то процессор продолжит обработку прерывания "1" и только
//после ее завершения перейдет к обработке прервыания "0". Если же запросы на обработку прерываний
//ПОДгрупп 0 и 1 возникли одновременно, то первым обработается прерывание ПОДгруппы 0.
NVIC_SetPriorityGrouping(4); //В данном процессоре под группы/подгруппы отведено только 3 бита, т.е. будет 8 групп и 0 подгрупп

priorityGroup = NVIC_GetPriorityGrouping(); //прочитаем группировку прерываний для дальнейшего пользования

//запретим прерывания от таймеров общего назначения 0 и 1
NVIC_DisableIRQ(TIM0_IRQn);
NVIC_DisableIRQ(TIM1_IRQn);
//и сбросим "висящие" флаги этих прерываний
NVIC_ClearPendingIRQ(TIM0_IRQn);
NVIC_ClearPendingIRQ(TIM1_IRQn);

//Настроим прерывание таймера 0
NVIC_EnableIRQ(TIM0_IRQn); //разрешим
priority = NVIC_EncodePriority(priorityGroup, IRQ_PRIORITY_10K, 0); //кодирование приоритета
NVIC_SetPriority(TIM0_IRQn,priority); //задание приоритета
//Настроим прерывание таймера 1 (аналогично)
NVIC_EnableIRQ(TIM1_IRQn);
priority = NVIC_EncodePriority(priorityGroup, IRQ_PRIORITY_1K, 0);
NVIC_SetPriority(TIM1_IRQn,priority);

//Настройка таймеров
//Настройка таймера 0 на 10 кГц
NT_TIMER0->INTSTATUS_INTCLEAR_bit.INT = 1; //очистка флага прерывания таймера
NT_TIMER0->RELOAD = 10000-1; //Частота тактирования - 100 МГц. Период таймера - 100000кГц/10кГц = 10000. 10000-1 пишется, т.к. таймер считает с нуля.
NT_TIMER0->CTRL = ( (1 << 0) | (1 << 3) ); //Запуск таймера (нулевой бит регистра CTRL) и разрешение прерываний (третий бит)
//Настройка таймера 1 на 1 кГц (аналогично)
NT_TIMER1->INTSTATUS_INTCLEAR_bit.INT = 1;
NT_TIMER1->RELOAD = 100000-1;
NT_TIMER1->CTRL = ( (1 << 0) | (1 << 3) );

EINT; //Разрешить прерывания

}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int16 main (void){
//Инициализация микроконтроллера: настройка таймеров, инициализаци периферийных устройств
InitCLK();

//копируем функции секции fastcode из флеша в оперативку
memcpy(&__fastcode_ram_start, &__fastcode_flash_start,((Uint32)(&__fastcode_ram_end) - (Uint32)(&__fastcode_ram_start)));
//копируем таблицу векторов прерываний isr_vector из флеша в оперативку, чтобы быстрее работало
memcpy(&__isr_vector_ram_start, &__isr_vector_flash_start,((Uint32)(&__isr_vector_ram_end) - (Uint32)(&__isr_vector_ram_start)));

//Инициализация периферии
DIO_init();
PWM_init();
//Инициализация таймеров общего назначения и прерываний
Timer_and_interrupt_init();
adc_init();


int a;


//бесконечный цикл

uint32_t res;

// periph_init();
// SysTick_Config(10000000);


NT_ADC->ACTSS_bit.ASEN0 = 1; //enable seq0
// NT_COMMON_REG->PWM_SYNC = 1 << 6; //enable pwm6



int b;

while(1)
{
a = iStart;
b = iOpen;

// HallCurr = myHallPos();
if (a > 0 & START == 0 & b > 0)
// if (START == 0)
{

NT_GPIOG->DATA |= (1 << 10);// MGN_OFF;
HallPrew = 0;
MotorStep = 2;
START = 1;

}


if (b == 0)
{
NT_GPIOG->DATA &= ~(1 << 10); // MGN_ON;

HallPrew = 0;
MotorStep = 0;
START = 0;
}

if(a == 0)
{
NT_GPIOG->DATA &= ~(1 << 10); // MGN_ON;
HallPrew = 0;
MotorStep = 0;
START = 0;
// NT_GPIOG->DATA |= (1 << 10);//MGN_OFF;
}


if (adc_irq_flag) {
adc_irq_flag = 0;
// BSP_LED_Toggle(LED1_MSK);
res = NT_ADC->SEQ[0].FIFO_bit.DATA;
// printf("%0.4fV | 0x%03x | %04d\n", 1.5f*((int)res-2048)/2048, res, res);
res = NT_ADC->DCVAL_bit[0].VAL;

}

}


}

//**************************************************************
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Таймер 1 кГц 1 (1 кГц)
void TIM1_IRQHandler (void)
{


static int Timer1K;

static int Timer2;
static int iCycle;
// static int bON;
static int HallCount = 0;
static int Tackt = 0;
int WH_ON =0;
int WH_OFF =0;

int WL_ON =0;
int WL_OFF =0;
int UH_ON =0;
int UH_OFF =0;

int UL_ON =0;
int UL_OFF =0;
int VH_ON =0;
int VH_OFF =0;

int VL_ON =0;
int VL_OFF =0;
// int val = 1500;
// int PWMBlinkingSpeed = 10;

int PWM_OFF = 1000;
int PWM_ON = 340;
static int sSimON = 1;
//========s===============
/*
if (sSimON>0)
{
if (sSimON == 1) HallCurr = 1;
sSimON++;
if (sSimON>10000)
{
HallCurr++;
sSimON = 2;

if (HallCurr>6) HallCurr = 1;
}

}
else

HallCurr = myHallPos();

*/
HallCurr = myHallPos();
Tackt = 0;
if (START)
{


if (Timer1K < 8000) Timer1K++;

Timer2++;

if (Timer2 > 1000)Timer2 = 0;

if ((HallCurr != HallPrew)&(HallCount < 10)) HallCount++;

if (HallCount > 2)
{
Tackt = (HallCurr != HallPrew);
MotorStep = HallCurr;
}
else
{

Tackt = (Timer1K < 1500)&(Timer2 > 150);
//------------------------
if (MotorStep == 0)
MotorStep = HallCurr;
else
MotorStep++;
//------------------------
if (MotorStep > 6)
MotorStep = 1;
}

if (MotorStep == 0)
MotorStep = HallCurr;
else
MotorStep++;
//------------------------
if (MotorStep > 6)
MotorStep = 1;

Tackt = (HallCurr != HallPrew);


if (Tackt)
{
Timer2=0;
iCycle++;



MotorStep = HallCurr;


/*HallCurr
1 - C
5 - C A
4 - A
6 - A B
2 - B
3 - B C
*/

switch (MotorStep)
{
case 1:

VL_ON = 0;
VH_ON = 0;

UL_ON = 0;
UH_ON = 1;

WL_ON = 1;
WH_ON = 0;

break;

case 2:

VL_ON = 1;
VH_ON = 0;

UL_ON = 0;
UH_ON = 1;

WL_ON = 0;
WH_ON = 0;

break;

case 3:

VL_ON = 1;
VH_ON = 0;

UL_ON = 0;
UH_ON = 0;

WL_ON = 0;
WH_ON = 1;
break;

case 4:

VL_ON = 0;
VH_ON = 0;

UL_ON = 1;
UH_ON = 0;

WL_ON = 0;
WH_ON = 1;

break;

case 5:

VL_ON = 0;
VH_ON = 1;

UL_ON = 1;
UH_ON = 0;

WL_ON = 0;
WH_ON = 0;

break;

case 6:

VL_ON = 0;
VH_ON = 1;

UL_ON = 0;
UH_ON = 0;

WL_ON = 1;
WH_ON = 0;


break;


default:
START = 0;
break;
}




HallPrew = HallCurr;
}


}

else
{
VL_ON = 0;
VH_ON = 0;

UL_ON = 0;
UH_ON = 0;

WL_ON = 0;
WH_ON = 0;

// UH_OFF;
// VH_OFF;
// WH_OFF;
HallMode = 0;
iCycle = 0;
Timer1K = 0;
Timer2 =0;
HallCount = 0;
MotorStep = 0;
}


if (START)
{

if (WL_ON)
{
NT_PWM6->CMPA_bit.CMPA = PWM_ON;
NT_PWM7->CMPA_bit.CMPA = PWM_OFF;
NT_PWM8->CMPA_bit.CMPA = PWM_OFF;
}
else
if (UL_ON)
{
NT_PWM6->CMPA_bit.CMPA = PWM_OFF;
NT_PWM7->CMPA_bit.CMPA = PWM_ON;
NT_PWM8->CMPA_bit.CMPA = PWM_OFF;
}
else
if (VL_ON)
{
NT_PWM6->CMPA_bit.CMPA = PWM_OFF;
NT_PWM7->CMPA_bit.CMPA = PWM_OFF;
NT_PWM8->CMPA_bit.CMPA = PWM_ON; // NT_PWM8->CMPA_bit.CMPA = val;
}


if (WH_ON)
{
NT_PWM0->CMPA_bit.CMPA = PWM_OFF;
NT_PWM1->CMPA_bit.CMPA = PWM_ON;
NT_PWM2->CMPA_bit.CMPA = PWM_OFF;
}
else
if (UH_ON)
{
NT_PWM0->CMPA_bit.CMPA = PWM_ON;
NT_PWM1->CMPA_bit.CMPA = PWM_OFF;
NT_PWM2->CMPA_bit.CMPA = PWM_OFF;
}
else
if (VH_ON)
{
NT_PWM0->CMPA_bit.CMPA = PWM_OFF;
NT_PWM1->CMPA_bit.CMPA = PWM_OFF;
NT_PWM2->CMPA_bit.CMPA = PWM_ON;
}

}
else
{
CurrPWM = 0;
NT_PWM6->CMPA_bit.CMPA = PWM_OFF;
NT_PWM7->CMPA_bit.CMPA = PWM_OFF;
NT_PWM8->CMPA_bit.CMPA = PWM_OFF;

NT_PWM0->CMPA_bit.CMPA = PWM_OFF;
NT_PWM1->CMPA_bit.CMPA = PWM_OFF;
NT_PWM2->CMPA_bit.CMPA = PWM_OFF;

}



NT_ADC->ISC = 1 << 0; //seq0
adc_irq_flag = 1;
NT_TIMER1->INTSTATUS_INTCLEAR_bit.INT = 1; //Сбросим флаг прерывания таймера
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//**************************************************************
//Таймер 10кГц № 0
void TIM0_IRQHandler (void)
{

NT_TIMER0->INTSTATUS_INTCLEAR_bit.INT = 1; //Сбросим флаг прерывания таймера
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
//Скважность работы диода 3 нарастает линейно с заданной скоростью, дидода 5 - ступенчато.
//Диоды 4 и 6 работают комплиментарно с диодами 3 и 5 соответственно.
NT_PWM7->CMPA_bit.CMPA += PWMBlinkingSpeed;
if (NT_PWM7->CMPA_bit.CMPA >= NT_PWM7->TBPRD)
{
NT_PWM7->CMPA_bit.CMPA = 0;
NT_PWM8->CMPA_bit.CMPA += 2000;
if (NT_PWM8->CMPA_bit.CMPA >= NT_PWM8->TBPRD)
NT_PWM8->CMPA_bit.CMPA = 0;
}
*/
//+++++++++++++++++++++++++++++++++++
int myHallPos()
{

int A=0;
int B=0;
int C=0;
int res = 0;


if(NT_GPIOH->DATA & (1 << 4)) //A
{
A = 4;
}


if(NT_GPIOH->DATA & (1 << 3)) //B
{
B = 2;
}


if(NT_GPIOH->DATA & (1 << 5)) //C
{
C = 1;
}



/*
//---------------------------
tFilterA = myFilter(NT_GPIOH->DATA & (1 << 4),tFilterA); //4

if (tFilterA >= FilterTime )
A = 4;

//---------------------------
tFilterB = myFilter(NT_GPIOH->DATA & (1 << 5),tFilterB); //3

if (tFilterB >= FilterTime )
B = 2;
//---------------------------
tFilterC = myFilter(NT_GPIOH->DATA & (1 << 3),tFilterC); //5

if (tFilterC >= FilterTime )
C = 1;
//---------------------------
*/
int Step = 1;

switch (A+B+C)
{
case 1:
return 4; //4
break;

case 5:
return 5;
break;

case 4:
return 6;
break;

case 6:
return 1;
break;

case 2:
return 2;
break;

case 3:
return 3;
break;
}

// 1 - C
// 2 - B
// 4 - A
// 3 - B - C
// 5 - A - C
// 6 - A - B

/*
последовательность сейчас
1: w- u+
2: v- u+
3: v- w+
4: u- w+
5: u- v+
6: w- v+

1 - C
5 - C A
4 - A
6 - A B
2 - B
3 - B C
*/
}
//+++++++++++++++++++++++++++++++++++

Re: Работа с АЦП

Добавлено: 05 фев 2021, 15:48
Лашкевич Максим
Это очень много кода для чтения, извините. Наблюдать переменные в реальном времени в VectorIDE нельзя. Для этого и сделан был драйвер CANOpen и UniCON. Крайне не советую писать программу с нуля, не модульно и в одном файле. Нужно взять проект моторконтролдемо и поменять под себя нужные части, после каждого изменения проверяя работоспособность. Там же можно и переменные смотреть в юниконе, и прошивать по CAN, и скелет программы типовой там весь написан.

Re: Работа с АЦП

Добавлено: 09 фев 2021, 09:44
Amelin!
С работой АЦП разобрались, пока без FIFO
на основе этой ветки
viewtopic.php?f=13&p=1353

Re: Работа с АЦП

Добавлено: 07 апр 2021, 08:20
BogatovNA!
Здравствуйте.
Видел ваше сообщение на форуме НИИЭТ по поводу неточности измерений АЦП.
Столкнулся со схожей проблемой.
Используя проект из репозитория, я настроил измерение по всем каналам АЦП с программным запуском и без аппаратного усреднения + вывод через printf. Скорость измерения (дискретизация) вышла в среднем 7мс. Проблема заключается в том, что разброс между пиковыми значениями порядка 150 дискрет.
Грешил на входной сигнал, но по осциллографу никаких шумов не наблюдается. Сталкивались ли вы с подобной проблемой?
Возможно ли, что это связано с внутренним опорным сигналом?

Re: Работа с АЦП

Добавлено: 07 апр 2021, 15:19
Лашкевич Максим
Слишком большой шум. У нас в статике есть ошибка, т.е. значения могут быть все или занижены или завышены относительно ожидаемого для этого напряжения. Но шума нет - дрожит пара разрядов. Ищите проблему с платой, разводкой, питаниями. Попробуйте прямо на вход микроконтроллера около прям ножки повесить кондёр на вход АЦП керамический - если шум упадёт, то точно плата. Ещё можно разрезать дорожку и подать на вход АЦП батарейку и резистивным делителем и конденсатором с малой длиной проводов - как источник стабильного сигнала.

Re: Работа с АЦП

Добавлено: 08 апр 2021, 13:31
BogatovNA!
Лашкевич Максим писал(а):
07 апр 2021, 15:19
Слишком большой шум. У нас в статике есть ошибка, т.е. значения могут быть все или занижены или завышены относительно ожидаемого для этого напряжения. Но шума нет - дрожит пара разрядов. Ищите проблему с платой, разводкой, питаниями. Попробуйте прямо на вход микроконтроллера около прям ножки повесить кондёр на вход АЦП керамический - если шум упадёт, то точно плата. Ещё можно разрезать дорожку и подать на вход АЦП батарейку и резистивным делителем и конденсатором с малой длиной проводов - как источник стабильного сигнала.
выявил некую связь с источником PLL. На входе стоит внешний источник тактового сигнала 24МГц. При настройке PLL на 100МГц и тактирования АЦП на 10МГц (DIV_ADC = 4) выявлены шумы с размахом в 150 дискрет.
При настройке PLL на 72МГц и тактирования АЦП на 12МГц (DIV_ADC = 2) размах шумов становится максимум 15 дискрет!
Аналогичное улучшение работы с ацп по сравнению с настройкой 100МГц/10Мгц наблюдается при настройках: 96МГц/12Мгц, 96МГц/8Мгц, 48МГц/12Мгц.

Зависимость для меня совершенно непонятная

Re: Работа с АЦП

Добавлено: 08 апр 2021, 14:05
Лашкевич Максим
Чем ниже частота, тем больше время измерения, тем сильнее усредняются помехи. Проведите опыт с конденсатором и батарейкой.

Re: Работа с АЦП

Добавлено: 12 апр 2021, 09:47
BogatovNA!
Лашкевич Максим писал(а):
08 апр 2021, 14:05
Чем ниже частота, тем больше время измерения, тем сильнее усредняются помехи. Проведите опыт с конденсатором и батарейкой.
Опыт с батарейкой показал аналогичные результаты. Я использовал предоставленный пример из репозитория с библиотечными функциями с минимальными изменениями. Как показала практика, настройка МК на частоту 72МГц и АЦП на 9МГц показывает результаты хуже, чем настройка на 72МГц и 12МГц соответственно.