Перейти к содержанию
    

Sonya

Участник
  • Постов

    15
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Информация о Sonya

  • Звание
    Участник
    Участник

Контакты

  • ICQ
    Array
  1. Частично решила проблему: 1) Внешний триггер нужно задавать только первому АЦП, а остальным запрещать. И это написано в мануале: Note: In multi ADC mode, when configuring conversion trigger by an external event, the application must set trigger by the master only and disable trigger by slaves to prevent spurious triggers that would start unwanted slave conversions. 2) Нужно после срабатывания прерывания по DMA АЦП переключать в режим ADC_Mode_Independent, перед следующим преобразованием. И это тоже написано в мануале: Note: If the conversion sequence is interrupted (for instance when DMA end of transfer occurs), the multi-ADC sequencer must be reset by configuring it in independent mode first (bits DUAL[4:0] = 00000) before reprogramming the interleaved mode. Правда DUAL[4:0] - это на самом деле MULTI[4:0]. Как всегда, мануал stm тренирует у разработчиков бдительность и смекалку. Но проблема до конца не решена...
  2. stm32f407 + interleaved mode ADC + DMA

    Нужно сделать вот что: запускать АЦП по внешнему сигналу (External trigger = EXTI line11). Режим работы АЦП при этом - interleaved mode с DMA (три АЦП подряд ацепируют один и тот же сигнал на входе). Инициализация АЦП проходит так (под копирку из примеров библиотеки стандартной периферии): static void ADC_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; DMA_InitTypeDef DMA_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* Enable peripheral clocks *************************************************/ RCC_AHB1PeriphClockCmd( ADC1_2_CHANNEL_GPIO_CLK , ENABLE); RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA2 , ENABLE); RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1 , ENABLE); RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC2 , ENABLE); RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC3 , ENABLE); /* Configure ADC Channel 0 pin as analog input *****************************/ GPIO_InitStructure.GPIO_Pin = GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIO_PORT, &GPIO_InitStructure); /* DMA2 Stream0 channel 0 configuration **************************************/ DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aADCTripleConvertedValue[0]; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = num; //сколько точек взять для преобразования DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA_STREAMx, &DMA_InitStructure); /* DMA2_Stream0 enable */ DMA_Cmd(DMA2_Stream0, ENABLE); /* ADC Common configuration *************************************************/ ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInit(&ADC_CommonInitStructure); /* ADC1 regular channel 0 configuration ************************************/ ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Falling; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_Ext_IT11; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles); ADC_DMACmd(ADC1, ENABLE); /* ADC2 regular channel 0 configuration ************************************/ ADC_Init(ADC2, &ADC_InitStructure); /* ADC2 regular channel 0 configuration */ ADC_RegularChannelConfig(ADC2,ADC_Channel_0, 1, ADC_SampleTime_3Cycles); /* ADC3 regular channel 0 configuration ************************************/ ADC_Init(ADC3, &ADC_InitStructure); /* ADC3 regular channel 0 configuration */ ADC_RegularChannelConfig(ADC3, ADC_Channel_0, 1, ADC_SampleTime_3Cycles); } Внешней командой (по Modbus на UARTе) инициализируется вход, на который приходит синхроимпульс, разрешаются прерывания и включается АЦП: RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; GPIOC->MODER &=~GPIO_MODER_MODER11; GPIOC->PUPDR &=~GPIO_PUPDR_PUPDR11; SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI11_PC; EXTI->IMR |=(EXTI_IMR_MR11); EXTI->FTSR |=(EXTI_FTSR_TR11); DMA2_Stream0 -> CR |= DMA_SxCR_TCIE; NVIC_EnableIRQ(DMA2_Stream0_IRQn); ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_Cmd(ADC2, ENABLE); ADC_Cmd(ADC3, ENABLE); И что происходит в обработчике DMA: void DMA2_Stream0_IRQHandler(void){ DMA2 -> LIFCR |= DMA_LIFCR_CTCIF0; //обнуляем флаг Transfer Complete ADC_MultiModeDMARequestAfterLastTransferCmd(DISABLE); ADC_Cmd(ADC1, DISABLE); ADC_Cmd(ADC2, DISABLE); ADC_Cmd(ADC3, DISABLE); } Синхронизация не работает при таком раскладе. Прерывание DMA срабатывает не связано с внешним сигналом: то до его спадающего фронта, то после. Если эту ножку оторвать, то АЦП вообще не запускается (по крайней мере в обработчик DMA не входит). То есть как-то этот сигнал всё-таки действует. Подскажите, пожалуйста, что я делаю не так? Я так понимаю, что секрет в этих двух строчках: ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Falling; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_Ext_IT11; Выставление разных ADC_ExternalTrigConvEdge дает одинаковую картину (только если не выставить его в None). Внешний сигнал с синхроимпульсом проверен - перепроверен: четко идет раз в 100мкс длительностью 50 мкс. Фронты адекватные. Если в обработчике DMA не запрещать ADC, то это прерывание срабатывает каждые ~20мкс. Где-то в мануале было написано, что надо бы отрубать периферию от DMA каждый раз при срабатывания прерывания. Если честно, не очень понимаю, как правильно инициализировать EXTI line11. EXTI->IMR |=(EXTI_IMR_MR11); <- это пережитки прошлой программы, но вроде как и здесь как-то также должно быть или нет (внешний сигнал приходит на gpioc.11)? EXTI->FTSR |=(EXTI_FTSR_TR11); В программе никаких прерываний больше нет, то есть DMA ничего не должно мешать (команда по modbus приходит только один раз в начале). Раньше версия программы была немного иной: АЦП запускалось в обработчике прерывания по внешнему сигналу. Всё работало. Но потребовалось изменить код, чтобы АЦП запускалось триггером по этому внешнему сигналу. У меня возникло подозрение, что возможно эта опция запуска АЦП по триггеру внешним сигналом в режиме interleaved + DMA вообще не работает в stm... Может ли такое быть? ) Внешняя команда, приходящая по Modbus, обрабатывалась прямо в обработчике по таймеру 5. Видимо, из-за этого неправильно синхронизировалось АЦП с первым приходом фронта внешнего импульса (т.к. прерывание tim5 приоритетней, чем dma2_stream0). Поэтому сейчас этот код добавлен после ADC_config(). А в обработчик по таймеру, где раньше выполнялись эти строчки, добавлено выставление флага flag = 1; , проверка которого идет в основном цикле программы. ADC_Config(); RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; GPIOC->MODER &=~GPIO_MODER_MODER11; GPIOC->PUPDR &=~GPIO_PUPDR_PUPDR11; SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI11_PC; EXTI->IMR |=(EXTI_IMR_MR11); EXTI->FTSR |=(EXTI_FTSR_TR11); DMA2_Stream0 -> CR |= DMA_SxCR_TCIE; NVIC_EnableIRQ(DMA2_Stream0_IRQn); while(1){ if (flag ==1) { flag =0; ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_Cmd(ADC2, ENABLE); ADC_Cmd(ADC3, ENABLE); } } И всё же непонятно, почему по второй, третьей .... и т.д. команде DMA срабатывает в какие-то произвольные моменты времени, несинхронизированно с внешним сигналом. И почему , если ADC не выключать или выключать и включать прямо в обработчике DMA, то DMA срабатывает каждые ~20мкс, а не раз в 100мкс...
  3. АЦП stm32f205

    hd44780, разный time selection выставляла, не помогло. ViKo, я задаю JL[1:0] = 3, значит первое преобразование описывается в JSQ1[4:0]. Думаю, что у меня просто АЦП сгорел.
  4. АЦП stm32f205

    Не работает АЦП stm32f205. Собственные мысли, где может быть ошибка, кончились, поэтому обращаюсь с просьбой помочь разобраться. Пытаюсь следить за напряжением на PA.1, там где положено быть первому каналу АЦП (как я понимаю любого из трех модулей АЦП). Опорное напряжение = 3,3В. Напряжение на PA.1 меняю от 0,2 до 1,5 В. Вот мой скромный код: RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;//тактирование порта А GPIOA->MODER |= GPIO_MODER_MODER1; //analog mode PA.1 GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR1; //No pull-up, pull-down PA.1 RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //тактирование АЦП ADC1->CR1 &= ~ADC_CR1_RES; //12-битный результат ADC1->CR2 |= ADC_CR2_CONT;//Continuous conversion - не понимаю, что это такое, роли не играет //ADC1->CR1 |= ADC_CR1_JAUTO; //не играет роли ADC1->CR2 &= ~ADC_CR2_ALIGN;//выравнивание по правому краю ADC1->JSQR |= ADC_JSQR_JL;//разрешаю все четыре преобразования ADC1->JSQR |= ADC_JSQR_JSQ1_0;//выставляю, что первое преобразование - это будет с моего первого канала на PA.1 ADC1->CR2 |= ADC_CR2_ADON;//разрешаю АЦП ADC1->CR2 |= ADC_CR2_JSWSTART; //стартую while (!(ADC1->SR & ADC_SR_JEOC));//жду окончания INA = ADC1-> JDR1;//забираю результат в регистр INA После выполнения этих нехитрых операций в регистре INA появляется результат в десятичном виде: 4001 счета при 0,2В на PA.1 и 4063 счета при 1,5В на PA.1. Получается контроллер нагло врет, выдавая мне эти результаты. Но почему?
  5. вот оно че оказывается... пожалуйста, переведите меня в "участники" для отправки сообщения это было моё десятое сообщение :)
  6. А, до меня дошло :D Если в отдельном файле сделать массив с помощью WinHex, то да, всё хорошо будет.
  7. Вы предлагали rbf-файл подключить с помощью include, а не массивом. На массив естественно компилятор не жалуется, просто, имхо, массив размером 30кб в коде программе выглядит не эстетично. Поэтому и хочу задействовать ttf-файл, разбить его и подключать с помощью include.
  8. Я и хочу включить файл с помощью include, но так прокатит подключить только ttf, на rbf-файл компилятор жалуется. Только оба эти файла слишком здоровые для памяти моей атмеги, поэтому и возникла проблема их раздробить на более мелкие (и поочередно писать в dataflash контроллером). WinHex помог :)
  9. Ага, только у меня ttf весит 394639 байт, а rbf 98023 байта. В WinHex есть такая функция "C source" - класс :) Копирует из rbf не только данные в том виде, который нужен, но и код добавляет, сразу получается: unsigned char data[625] = { 0xFF, 0xFF, 0x62, 0xFF, 0x3C, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, } Вещь! Но я, дабы не загромождать код программы, хотела бы конечно делать: #include и ttf-файл. Правда не совсем пока понимаю, как сопоставить ttf и rbf если пытаться дробить ttf... Получается что байт данных в rbf равнозначен примерно 4 байтам в текстовом представлении. Но об чем говорят еще 2547 байт ttf-файла непонятно (394639-98023*4=2547).... В принципе может и так вставлю массив из rbf C-source'ом :) Если ниче больше в голову не придет
  10. Спасибо! Я и не знала, что есть редакторы, работающие с двоичными данными. Скачала WinHEx, буду изучать, чего он умеет. Дело в том, что в будущем (надеюсь ближайшем) атмега будет получать данные из CAN-сети, поэтому не хочу сейчас заморачиваться с другими интерфейсами. В данный момент хотелось бы просто проверить будет ли альтера прошиваться или нет. Вот. Буду пытаться резать ttf :)
  11. В том и состоит суть вопроса, как порезать rbf так, чтобы получить файлы ttf, указывающие на куски rbf, дабы использовать эти куски в прошивке атмеги как писал Леонид Иванович: const __hugeflash char FPGA_Config[]={ #include "..\Altera\MyProj.ttf" }; Другими словами я хочу несколько раз перепрошить атмегу, прописывая ttf, указывающие на разные куски rbf, и выставляя в каждой новой прошивке атмеги новые адреса для записи в датафлэш at45db (чтобы уместить 98килобайтный rbf в датафлэш) Можно ли так сделать вообще? Если нет, то какие пути решения этой проблемы есть? (кроме того, чтобы взять микроконтроллер с большим объемом внутр. флэш). О каком ПЗУ идет речь? Флэш атмеги программирую AVRISP, dataflash at45db программирует атмега, ПЛИС не имеет ПЗУ :) Но ее программировать будут по SPI at45db напару с атмегой.
  12. Подскажите, пожалуйста, а можно ли каким-нибудь образом разбить файл .rbf на несколько частей меньшего объема, причем чтобы в коде программы контроллера ссылаться на ttf ? (то есть чтобы несколько раз ссылаться на ttf, который будет содержать в себе поочередно тот или иной кусок дробленного .rbf) Моя проблема в том, что надо конфигурировать EP1K50 (Acex 1K), файлы .rbf проекта весят 98кбайт, а пытаюсь конфигурировать Атмегой 32.... Хочу попробовать разбить rbf и по кусочкам заливать его в микросхему памяти (at45db). А потом из памяти уже в ПЛИС.
×
×
  • Создать...