|
SAM4S, Ничего не выходит |
|
|
|
 |
Ответов
(1 - 63)
|
Oct 14 2014, 18:26
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Вот посмотрите... Разберетесь? CODE void arm_hardware_pioa_outputs(unsigned long opins, unsigned long initialstate) { #if CPUSTYLE_AT91SAM7S
AT91C_BASE_PMC->PMC_PCER = 1UL << AT91C_ID_PIOA; // разрешить тактированние этого блока
AT91C_BASE_PIOA->PIO_SODR = (opins & initialstate); // Установка единицы в регистре данных AT91C_BASE_PIOA->PIO_CODR = (opins & ~ initialstate); // Установка нулей в регистре данных
AT91C_BASE_PIOA->PIO_OER = opins; // Разрешение выхода AT91C_BASE_PIOA->PIO_PPUDR = opins; // disable pull-up resistors AT91C_BASE_PIOA->PIO_MDDR = opins; // Disable open drain output
#elif CPUSTYLE_ATSAM3S || CPUSTYLE_ATSAM4S
PMC->PMC_PCER0 = (1UL << ID_PIOA);
PIOA->PIO_SODR = (opins & initialstate); // Установка единицы в регистре данных PIOA->PIO_CODR = (opins & ~ initialstate); // Установка нулей в регистре данных
PIOA->PIO_OER = opins; // эти выводы на вывод - похоже, при работе с периферийными устройствами не требуется. PIOA->PIO_PUDR = opins; PIOA->PIO_MDDR = opins; // Disable open drain output
#elif CPUSTYLE_STM32F10X
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; /* I/O port A clock enable */ __DSB(); // Установка начального состояния битов GPIOA->BSRR = (GPIO_BSRR_BS0 * (initialstate & opins)) | (GPIO_BSRR_BR0 * (~ initialstate & opins)); // Установка режима выводов arm_stm32f10x_hardware_pio_prog(GPIOA, opins, 0, 1); /* Установить CNF=0 и MODE=1 для указанных битов */
#elif CPUSTYLE_STM32F4XX
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; /* I/O port A clock enable */ __DSB(); // Установка начального состояния битов arm_stm32f4xx_hardware_pio_setstate(GPIOA, opins, initialstate); // Установка режима выводов arm_stm32f30x_hardware_pio_prog(GPIOA, opins, 1, 1, 0, 0); /* mode, speed, pupdr, typer */
#elif CPUSTYLE_STM32F30X || CPUSTYLE_STM32F0XX
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* I/O port A clock enable */ // Установка начального состояния битов GPIOA->BSRR = (GPIO_BSRR_BS_0 * (initialstate & opins)) | (GPIO_BSRR_BR_0 * (~ initialstate & opins)); // Установка режима выводов arm_stm32f30x_hardware_pio_prog(GPIOA, opins, 1, 1, 0, 0); /* mode, speed, pupdr, typer */
#else #error Undefined CPUSTYLE_XXX #endif }
Сообщение отредактировал IgorKossak - Oct 15 2014, 08:16
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
Oct 14 2014, 18:29
|

Частый гость
 
Группа: Свой
Сообщений: 78
Регистрация: 23-03-11
Из: Россия
Пользователь №: 63 824

|
Все зависит от того чем Вы предпочитаете пользоваться(среда разработки), общение напрямую при помощи регистров или используя библиотеку ASF. В простейшемслучае если используем ASF добавить в файл conf_board.h: Код #define PIN_OUT IOPORT_CREATE_PIN(PORTB, 0) // Смотря куда у вас там LED подключен или какую ногу хотите использовать где то в board_init(void) Код ... ioport_configure_pin(PIN_OUT, IOPORT_DIR_OUTPUT | IOPORT_INIT_LOW); ... где то в коде: Код ... ioport_set_pin_level(PIN_OUT, 1) для вЫсокого уровня (0 - для низкого уровня) ... Если нужно просто перекидывать состояние одно из другой Код ... ioport_toggle_pin_level(PIN_OUT) ... Если по поводу регистров - то велком в Skype: контакты в личке. По возможности раскажу, что да как
|
|
|
|
|
Oct 14 2014, 19:15
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Вот посмотрите... Разберетесь? Честно говоря сложновато... совсем сложновато... Цитата Все зависит от того чем Вы предпочитаете пользоваться(среда разработки), общение напрямую при помощи регистров или используя библиотеку ASF. Использую Atmel studio 6.2. Хотел использовать напрямую регистры, но теперь начинаю понимать, что наверное был не совсем прав. Цитата А еще надо не путать даташит и рефернс мануал. В одном из них ответов не будет Столько мануалов уже пересмотрел-голова кругом + на работе выскачила проблема с установкой студий (они не хотели устанавливать какой то там компонент от вижуал студии, поэтому пришлось установить её отдельно) ну пока суть да дело весь день провозился... А есть какая нибудь литература по этому поводу например книжка, наверняка америкосы написали что то, я пока нашёл только The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4, но не всматривался в неё.
|
|
|
|
|
Oct 14 2014, 19:23
|

Частый гость
 
Группа: Свой
Сообщений: 78
Регистрация: 23-03-11
Из: Россия
Пользователь №: 63 824

|
Цитата(Грендайзер @ Oct 14 2014, 22:15)  А есть какая нибудь литература по этому поводу например книжка, наверняка америкосы написали что то, я пока нашёл только The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4, но не всматривался в неё. В данной книги описано ядро примеры работы с ним. Его структура. И т.д. На самом деле Код, который вам дал Genadi Zawidowski чоень подробно и хорошо расписывает, как работать с регистрами. Я дал пример для студии с использованием ASF. Вам осталось выбрать, что больше по душе. Если есть опыт работы с другими МК, то я бы советовал все же начать с регистров(но при условии что время не жмет и нет дедлайна) и вдумчивого разглядывания блок-схемы. А тогда уже будет понятно, как делать все остальное. Ну и естественно вопросы на форуме) + поиск А если нужно быстро - то имхо ASF даст вам быстро работающий результат без мыслей как это работает. Хотя, без чтения примеров, все же не обойдетесь
|
|
|
|
|
Oct 14 2014, 19:52
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Если есть опыт работы с другими МК, то я бы советовал все же начать с регистров Я только за, только не могу адреса регистров найти... Правда на АЦП, ЦАП и пр. есть вроде, а вот адреса и названия регистров управления GPIO найти не могу  Куда там писать что без ф-ций, адреса так сказать явки))) И ещё вопросик, что такое io_id? На сайте атмела нашёл список ф-ций для управления портами, среди которых, к примеру, gpio_set_pin_high(io_id); Как я понял эта ф-ция должна задрать порт в 1, ну я и пишу Код #include <asf.h> #include "conf_board.h" #include "compiler.h" #include "pio.h"
int main (void) { gpio_set_pin_high(PORTB);
} А он говорит, что не знает что такое PORTB..
Сообщение отредактировал Грендайзер - Oct 14 2014, 20:05
|
|
|
|
|
Oct 15 2014, 05:15
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
В АРМах не принято порты буквами называть. И на самом деле в АРМах все примерно также как и везде. ЗАпись по адресам регистров и все счастливы. В большом рефренс мануале есть адреса всех регистров. Но так как их реально много обычно адресами никто не пользуется. Практически во всех средах к процам есть заголовочный файл (его чуть ли не сам АРМ требует производителей проца делать). В этом файле собраны все адреса и им даны понятные названия. Стандарта правда нет.
LPC, например делает так LPC_GPIO1 -> FIODIR |= (1 << 26); LPC_GPIO1 -> FIOCLR = (1 << 26) это обращение в 1 порт 26 ногу.
Так что вам надо найти идиологию как делает атмел, найти этот файлик и все поедет. Я собственно сейчас поймал себя на мысли что уже давно не думал над тем какой адрес и смещение имеет тот или иной регитср.
Попробуйте кстати еще поглядеть кейл. Не знаю есть у него поддержка этого проца или нет, если есть, то у них самый логичный и простой путь работы с процами. Заголовочные файлы что лежат у них в среде, мне кажутся самыми понятными по структуре и они делают базовый проект куда уже правильные файлы подключены.
Одно только надо учесть что АРМ сложнее АВР. У него порт не только на вход - выход настраивается. Бывают еще варианты что порт выбирает режим работы подтяжка к 0, к 1, свободный, повторитель. У стм еще бывает можно выбрать макс частоту шевеления ноги, на малой меньше тока жрет. Потом на ножки выводятся внутренние модули, причем иногда один модуль на разные ноги можно вывести, и потому обычно нога имеет несколько функций, GPIO, UART, ADC, SPI. И эти функции так же настраиваются.
Я не видел мануал от вашего проца, а в LPC прям есть глава GPIO и там подробно написано что надо настроить чтобы все было хорошо
|
|
|
|
|
Oct 15 2014, 06:49
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Нашёл в студии заголовочник "sam4sd32c.h", там дефайнами обозначены адреса регистров, как я понял, но за что регистр отвечает... хз... буду дальше копать... За совет с кейлом спасибо, попробую в нём порыться... Фух, прозрел, нашёл таки в даташите, начиная с 577 странице. Приведены все имена и адреса регистров. Правда с использованием имён в студии проблемы почему то, ну да бог с ним... Впрочем конечно количество этих регистров и впрямь громадно, так что так вот с ходу разобраться не выйдет
|
|
|
|
|
Oct 15 2014, 06:52
|
Знающий
   
Группа: Свой
Сообщений: 583
Регистрация: 7-06-06
Из: Таганрог
Пользователь №: 17 840

|
Цитата(Грендайзер @ Oct 15 2014, 10:01)  Нашёл в студии заголовочник "sam4sd32c.h", там дефайнами обозначены адреса регистров, как я понял, но за что регистр отвечает... хз... буду дальше копать... За совет с кейлом спасибо, попробую в нём порыться... PIOA->PIO_OWER = (PIO_OWER_P0); //Enable write ODSR PA0 PIOA->PIO_OER = (PIO_OER_P0); //Output Enable PA0 PIOA->PIO_PER = (PIO_PER_P0); //PIO Enable (default) PA0 int main(void) while(1){ PIOA->PIO_ODSR ^= PIO_ODSR_P0; }
|
|
|
|
|
Oct 15 2014, 08:14
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
обычно хорошим тоном бывает давать в заголовочном файле имена по мануалу. То есть как в мануале регистр называется такой обычно дефайн и надо искать А еще хорошим тоном бывает смотреть апликайшен ноты. Там прям по шагам написано что да как и куда, но это уже на периферию, на ноги там не будет... Вообще в целом вам точно нужен именно этот проц? Атмел в рейтинге понятных мануалов далеко не на первых местах. В лидерах, тексас, филипс.... У филипса на NXP в начале главы про модуль, прям списком идет что надо настроить чтобы работало - очень удобно. А СТМ идет по пути выдачи пользователю библиотеки с понятными функциями и непонятным функционалом. У атмела же вроде тоже что-то подобное есть, функции должны быть открыты, можно в них залезть и понять как работают...
|
|
|
|
|
Oct 15 2014, 09:46
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Грендайзер @ Oct 15 2014, 08:49)  Нашёл в студии заголовочник "sam4sd32c.h", там дефайнами обозначены адреса регистров, как я понял, но за что регистр отвечает... хз... буду дальше копать... За совет с кейлом спасибо, попробую в нём порыться... Фух, прозрел, нашёл таки в даташите, начиная с 577 странице. Приведены все имена и адреса регистров. Правда с использованием имён в студии проблемы почему то, ну да бог с ним... Впрочем конечно количество этих регистров и впрямь громадно, так что так вот с ходу разобраться не выйдет  У меня были похожие ощущения, когда после 8051 я пересаживался на Cortex. Нужно понять две вещи, и тогда многое станет ясно (условие - Вы сечёте в языке C, из чего я исхожу). 1. Для Cortex фирма ARM попыталась с самого начала предотвратить разброд и шатание в части кода и выработала стандарт CMSIS. Суть его не только в том, что этот стандарт публикует функции доступа к ядру и базовой периферии Cortex, общие для всех, но и предписывает соглашения касаемо структуры заголовочных файлов, наименований переменных, регистров и функций. Производители начали придерживаться этого стандарта. 2. Для доступа к регистрам периферии синтаксически используются структуры (struct), а не "линейный" набор адресов каждого регистра. Для этого (см. CMSIS-совместимый "главный" заголовочный файл вашего процессора) определяется адрес базового регистра периферии, ему дается разумное имя (скажем, USART1, ADC2, и т.д.), а уже относительно него идут все регистры этой периферии. В результате практически для всех известных Cortex синтаксис идентичен. Например, доступ к регистру данных USART1 осуществляется как к полю структуры и будет выглядеть как: USART1->DATA = 0x0D; Ну, регистр данных может иметь несколько иное название, чем DATA, но принцип остается. По крайней мере уж USART1 точно так называется во всех пока мне бывших доступных Cortex. А названия "подчиненных" регистров USART1, как верно упомянул Golikov A, как правило совпадают с именами из мануала. Остальное схоже с любым микроконтроллером: биты и поля в регистре, их действие, и т.п.
|
|
|
|
|
Oct 15 2014, 12:50
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
а я бы сказал что так делать не надо, по описанной выше причине. Не надо делать своих дефайнов к ногам. Свои дефайны могу быть из раздела DIAGNOSTIC_LED_ON, DIAGNOSTIC_LED_OFF, за которыми скрыть работу с ножкой порта, но через стандартные дефайны из заголовочного файла. ИМХО конечно... Цитата , т.к. обращение напрямую к регистрам конечно не самый красивый способ не соглашусь. Это самый прямой и быстрый способ. Если не брать чужую библиотеку, надо писать свою, где функции настройки просто имеют внутри прямой доступ к регистрам. Это самый короткий, прямой путь без сюрпризов. Почему он не красив?
|
|
|
|
|
Oct 15 2014, 13:00
|

Частый гость
 
Группа: Свой
Сообщений: 78
Регистрация: 23-03-11
Из: Россия
Пользователь №: 63 824

|
Цитата(Golikov A. @ Oct 15 2014, 15:50)  а я бы сказал что так делать не надо, по описанной выше причине. Не надо делать своих дефайнов к ногам. Да дело же не в дефайнах - это идеология ASF от Атмела. А так, да - стоит использовать только дефайны для удобства чтения и создания переносимости. А по поводу скорости работы, кто же спорит. Напрямую всегда быстрее, чем окольными путями(ASF, STD Periph Lib и т.д, правда все зависит от реализации этих библиотек)
|
|
|
|
|
Oct 15 2014, 13:03
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Грендайзер @ Oct 15 2014, 13:55)  KnightIgor, спасибо, CMSIS обязательно изучу, т.к. обращение напрямую к регистрам конечно не самый красивый способ. Впрочем и работа с набором непонятных ф-ций то же не особо доставляет. Всегда пожалуйста, но мне кажется, Вы не совсем поняли: CMSIS не исключает обращения к регистрам напрямую. Она даже поощряет это, но вводит некоторые правила наименования тех самых регистров и битов в них, а также принцип доступа к периферийным регистрам как к полям некой структуры. Самих функций в CMSIS немного и касаются они только ядра и базовой периферии, то есть NVIC (контроллера прерываний), SYSTICK (генератора системных тиков) и некоторых других основ. Вам нужно, - и прислушайтесь к этому совету, - сначала изучить и применить периферийную библиотеку для Вашего процессора. Это надстройка над регистрами. Пусть многие ругают такие библиотеки и их индусских воплотителей, но они очень помогают для быстрого старта, потому что имеют сами за себя говорящие имена функций и параметры, скрывающие внутреннюю суть тех самых регистров и битов. И кстати, не все такие библиотеки плохи: для EFM32 они просто замечательны.
|
|
|
|
|
Oct 15 2014, 13:39
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Это самый короткий, прямой путь без сюрпризов. Почему он не красив? А действительно, почему?! Наверное Вы правы!!! В конечном итоге можно будет процесс программирования сделать немного похожим на программирование тех же АВР Цитата А по поводу скорости работы, кто же спорит. Напрямую всегда быстрее, чем окольными путями(ASF, STD Periph Lib и т.д, правда все зависит от реализации этих библиотек) А вот этот момент мне критичен. Вообще работаю с ПЛИС поэтому всегда знаю, сколько тактов у меня на что уходит, и если такого понимания нет чувствую себя немного не уютно. Но создавать свои проекты с учётом временных особенностей кристалла крайне сложно и долго, поэтому, и решил где возможно использовать готовые решения (например тот же Nios), облегчает жизь, но не стоимость изделия. Так что чёткое понимание это есть хорошо, правда в этом случае, придётся перейти на ассемблер, но это уже черезчур. Времени конечно нет, но его никогда нет. Тут советывался с одним коллегой, он работает с ядром ARM где то пол года, говорит что даже не стал вникать в эти ф-ции. Начал сразу писать свои библиотеки (впрочем у него огромный опыт работы с АВР и чего он там для них токо не писал).
Сообщение отредактировал Грендайзер - Oct 15 2014, 13:43
|
|
|
|
|
Oct 15 2014, 14:17
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
Правда как всегда по середине. Я всегда за то что нельзя использовать чужой код без проверки. Есть люди что верят библиотекам и даже не сморят что там внутри, а бывает всякое. Отрицать библиотеки тоже не правильно, часто они ускоряют процесс и делают код удобным для совместной работы, легче вникать что там понаделано.
Претензии у меня к ним такие. Библиотеки часто грешат, особенно те функции что настраивают сложную периферию тем что считают процессор в состоянии после ресета. А если есть бутлоадер и там уже что-то настроено? Пару раз так обсерался, не проверил и получил гемор и отладку...
А вот число тактов на команду - это суровый момент, процы имеют и схемы пред выбора команд, и конвейер и прерывания, и контроллер прерываний, не всегда у вас получится уследить за числом тактов%) да и компилятор помогает. А вот от Ассемблера я бы вас предостерег, мне кажется уже не того уровня техника. Только ассемблерные вставки в критических секциях не более, а то слишком дорого будет обслуживать проект.
Хотя все изложенное ИМХО
|
|
|
|
|
Jul 29 2015, 09:54
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Здравствуйте! Продолжаю мучить ATSAM4S32C. Дошёл до ЦАП и возникло 2 вопроса. 1) В электрических параметрах на встроенный ЦАП указан параметр Startup Time - что это? 2) В этих же электрических данных указано, что максимальная тактовая частота ЦАП составляет 50МГц. Но максимальная частота ядра достигает 120МГц. Частота ядра, как собственно и переферии есть Master Clock (MCK) которая ирёт с контроллера управления питанием Power Management Controller (PMC). В описаниии на ЦАП указано: The DACC uses the master clock (MCK) divided by two to perform conversions. Т.о. если я правильно понимаю, либо частота ядра не должна превышать 100МГц (что на 20МГц ниже чем максимальная) либо отказаться от использования встроенного ЦАП?  С АЦП у меня такой проблемы не возникло, т.к. тот имеет свой собственный делитель частоты. Но вот в ЦАПе я такого не обнаружл  Как быть? Что делать? Кто виноват?
|
|
|
|
|
Aug 5 2015, 10:10
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Всем доброго времени суток. Опять столкнулся с проблемой, точнее с двумя. Первое - никак не могу победить оптимизатор в AtmelStudio. Это сволочь помоиму мне палки в колёса тычит. А именно: написал программку которая принимает данные с АЦП, пропускает через ФВЧ и кладёт в ЦАП. CODE #include "sam.h" int din = 0; int dout = 0; int dacc_in = 0; int din_1 = 0; volatile int flag = 0;
int main(void) { SystemInit(); //--------------- Включение глобальных прерываний ----------------------------- __enable_irq (); //--------------- Enable Interrupts in NVIC ---------------------------- NVIC_EnableIRQ(DACC_IRQn); NVIC_EnableIRQ(ADC_IRQn); //--------------- Приоритет прерывания ЦАП ниже чем у АЦП NVIC_SetPriority (DACC_IRQn, 2); //----------- далее настройка переферии------------------------ . . . //---------------------------------------------------------------------- int main(void) { switch(flag) { case 0: // если прерывание от АЦП не произошло, моргать светодиодами { {PIOA -> PIO_CODR = PIO_CODR_P19 | PIO_CODR_P20;} for (int i = 0; i < 1000000; i ++){} {PIOA -> PIO_SODR = PIO_SODR_P19 | PIO_SODR_P20;} for (int i = 0; i < 1000000; i ++){} break; } case 1: // Если прерывание от АЦП было - гнать данные через ФВЧ { dacc_in = dout + din - din_1; dout = dacc_in * 0.9 + 600; din_1 = din; break; } default : {break;} } return 0; }
\\ Подпрограммы прерываний \\------------ АЦП---------------- void ADC_Handler( void ) { volatile int IRQ_sense = 0; IRQ_sense = ADC -> ADC_ISR & (ADC_IER_EOCAL | ADC_IER_EOC5); switch(IRQ_sense) { case ADC_IER_EOCAL : // автокалибровка АЦП { {PIOA -> PIO_CODR = PIO_CODR_P19 | PIO_CODR_P20;} {PIOA -> PIO_SODR = PIO_SODR_P19 | PIO_SODR_P20;} ADC -> ADC_IER = ADC_IER_EOC5; ADC -> ADC_CR = ADC_CR_START; return; } case ADC_IER_EOC5 : { flag = 1; // Говорим что было прерывание от АЦП din = ADC -> ADC_CDR[5] & ADC_CDR_DATA_Msk; // Данные с АЦП ADC -> ADC_CR = ADC_CR_START; // Вновь запускаем АЦП return; } default : {return;} } }
//-------------------------- ЦАП -------------------------------- void DACC_Handler( void ) { volatile int IRQ_sense = 0; IRQ_sense = DACC -> DACC_ISR;// & (DACC_ISR_EOC); DACC -> DACC_CDR = DACC_CDR_DATA(dout); return; } Так вот у меня программа лишь могргает светодиодами... Тупо.. В пошаговой отладке оказывается, что din меняет свое значение, а вот dout просто проскакивается, процессор его не замечая выполнят команду flag = 0 и всё. При этом если формулу фильтра вписать в функцию прерывания от АЦП то всё работает. В чём дело?
Сообщение отредактировал IgorKossak - Aug 5 2015, 19:37
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!
|
|
|
|
|
Aug 5 2015, 11:56
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Не грех посмотреть в сгенерённый код: куда dout там делся… А кто ж его знает... оптимизировался б...  Приведу кусочек дизассемблированного кода на рисуночке. P.S. Попробовал везде volatile напихать... амплитуда на выходе ЦАПа уменьшилась почти в 10 раз по сравнению с тем, что без волатиле, при том осциллограма сильно дёргается... Вообщем жесть какая то...
Сообщение отредактировал Грендайзер - Aug 5 2015, 11:57
Эскизы прикрепленных изображений
|
|
|
|
|
Aug 5 2015, 12:40
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
прошу прощения за ошибки допущенные при копировании. вот поправленный вариант CODE #include "sam.h"
int din = 0; int dout = 0; int dacc_in = 0; int din_1 = 0; volatile int flag = 0;
int main(void) { SystemInit(); //--------------- Enable Global Interrupts ----------------------------- __enable_irq (); //--------------- Enable Interrupts in NVIC ---------------------------- NVIC_EnableIRQ(DACC_IRQn); NVIC_EnableIRQ(ADC_IRQn); NVIC_SetPriority (DACC_IRQn, 2); while (1) { switch(flag) { case 0:// если прерывание от АЦП не произошло, моргать светодиодами { {PIOA -> PIO_CODR = PIO_CODR_P19 | PIO_CODR_P20;} for (int i = 0; i < 1000000; i ++){} {PIOA -> PIO_SODR = PIO_SODR_P19 | PIO_SODR_P20;} for (int i = 0; i < 1000000; i ++){} break; } case 1: // Если прерывание от АЦП было - гнать данные через ФВЧ { dacc_in = dout + din - din_1; dout = dacc_in * 0.9 + 600; din_1 = din; flag = 0; break; } default : {break;} } } return 0; }
\\ Подпрограммы прерываний \\------------ АЦП---------------- void ADC_Handler( void ) { volatile int IRQ_sense = 0; IRQ_sense = ADC -> ADC_ISR & (ADC_IER_EOCAL | ADC_IER_EOC5); switch(IRQ_sense) { case ADC_IER_EOCAL : // автокалибровка АЦП { {PIOA -> PIO_CODR = PIO_CODR_P19 | PIO_CODR_P20;} {PIOA -> PIO_SODR = PIO_SODR_P19 | PIO_SODR_P20;} ADC -> ADC_IER = ADC_IER_EOC5; ADC -> ADC_CR = ADC_CR_START; return; } case ADC_IER_EOC5 : { flag = 1; // Говорим что было прерывание от АЦП din = ADC -> ADC_CDR[5] & ADC_CDR_DATA_Msk; ADC -> ADC_CR = ADC_CR_START; return; } default : {return;} } }
//-------------------------- ЦАП -------------------------------- void DACC_Handler( void ) { volatile int IRQ_sense = 0; IRQ_sense = DACC -> DACC_ISR; DACC -> DACC_CDR = DACC_CDR_DATA(dout); return; } P.S. Процесс настройки переферии указывать не стал
Сообщение отредактировал IgorKossak - Aug 5 2015, 19:37
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!
|
|
|
|
|
Aug 5 2015, 13:14
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата какая там у вас битность ЦАП? не переполнится ли он таким макаром? 12 бит. Нет, не переполнится. Как я уже писал, всё работает если данный кусок кода поместить в ф-цию обработчика прерываний. Цитата Прерывания кстати где сбрасываются? В смысле? Прерывания срабатывают следующим образом 1) В процессе настройки переферии запускается ЦАП; 2) Когда завершается автокалибровка; 3) После автокалибровки запускается ЦАП; Все прерывания отрабатывают. И ещё пробовал отключать оптимизацию, код выполнялся правильно, но работал оооочень медленно.
|
|
|
|
|
Aug 5 2015, 13:43
|
Знающий
   
Группа: Свой
Сообщений: 583
Регистрация: 7-06-06
Из: Таганрог
Пользователь №: 17 840

|
Цитата(Грендайзер @ Aug 5 2015, 16:40)  прошу прощения за ошибки допущенные при копировании. вот поправленный вариант А где NVIC_SetPriority (ADC_IRQn, ?); Ладно, работает на приоритете по умолчанию. Где проверка на готовность DACC к преобразованию? P.S. volatile для локальной переменной функции это конечно ...
|
|
|
|
|
Aug 5 2015, 14:46
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
RabidRabbit, а не всё ли равно, с какой частотой следуют прерывания. Логика кода такая: сначала запускается ЦАП (как только выбран и включён канал, цап начинает работать автоматом, выдавая раз в 25 циклов прерывание о завершении преобразования). Затем запускается автокалибровка АЦП. Когда она завершится процессор уйдёт в прерывание и далее я считав регистр строчками Код volatile int IRQ_sense = 0; IRQ_sense = ADC -> ADC_ISR & (ADC_IER_EOCAL | ADC_IER_EOC5); сбрасываю флаги прерывания (сбрасываются при чтении) и определяю от чего прерывание - конец калибровки или конец преобразования. Затем строчкой Код ADC -> ADC_CR = ADC_CR_START; запускаю АЦП на преобразование. Даже если где то прерывания и пересекутся, то у ЦАП приоритет ниже чем у АЦП и он подождёт, пока тот отработает. Цитата возникло прерывание, а дальше? флаг наличия прерывания надо снять или он снимается чтением регистра? Да, строчками Код IRQ_sense = ADC -> ADC_ISR & (ADC_IER_EOCAL | ADC_IER_EOC5); IRQ_sense = DACC -> DACC_ISR; Флаг сбрасывается при чтении регистров. Цитата Я не понял, что это за фильтр и как он работает или не работает, так что о причинах сбоев гадать не берусь. Лампочки сдесь не причём. С сужу по наличию/отсутствию сигнала, который наблюдаю осциллографом. При правильной работе и лампочки должны мигать и сигнал быть... А там что то одно Цитата А где NVIC_SetPriority (ADC_IRQn, ?); Да, я не повышаю приоритет АЦП, я понижаю приоритет ЦАП. Цитата Где проверка на готовность DACC к преобразованию? Когда выдаётся прерывание о завершении преобразования ЦАП готов. Если бы он не был готов, то строчки кода фильтра помещённые в подпрограмму обработки прерывания с АЦП так же не отрабатывались бы.
Сообщение отредактировал Грендайзер - Aug 5 2015, 14:53
|
|
|
|
|
Aug 5 2015, 15:57
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Грендайзер @ Aug 5 2015, 17:46)  Лампочки сдесь не причём. С сужу по наличию/отсутствию сигнала, который наблюдаю осциллографом. При правильной работе и лампочки должны мигать и сигнал быть... А там что то одно  И как это может работать? Наводящий вопрос: сколько времени занимает выполнение вот этого участка кода? Код {PIOA -> PIO_CODR = PIO_CODR_P19 | PIO_CODR_P20;} for (int i = 0; i < 1000000; i ++){} {PIOA -> PIO_SODR = PIO_SODR_P19 | PIO_SODR_P20;} for (int i = 0; i < 1000000; i ++){} И ещё один вопрос: при этом у процессора вообще останется время на обсчёт фильтра?
|
|
|
|
|
Aug 5 2015, 17:08
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата И ещё один вопрос: при этом у процессора вообще останется время на обсчёт фильтра? Сколько угодно. Фильтр расчитывается лишь в том случае, если переменная flag == 1. Она устанавливается в 1 в функции обработки прерывания от АЦП, и сбрасывается в 0, как только завершился код фильтра для данного отсчёта поступившего с АЦП. После этого фильтр не считается, а моргают лампочки.... Цитата И как это может работать? Наводящий вопрос: сколько времени занимает выполнение вот этого участка кода? Не всё ли равно сколько времени занимает этот кусок кода? Его выполнение стопорнётся, как только придёт прерывание с переферии (ЦАП/АЦП). Впрочем я в ф-ции int main(void) я коментил лампочки и писал строчку типа Код dout = din; без всякого фильтра. Всё равно никакого эффекта. Как будто компилятор хочет всё выполнять в функциях прерывания, а на основную ему наср наплевать  При том самое интересное, что в основной ф-ции переменную flag процессор обнуляет, а вот фильтр банит...
Сообщение отредактировал Грендайзер - Aug 5 2015, 17:13
|
|
|
|
|
Aug 5 2015, 17:32
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Грендайзер @ Aug 5 2015, 20:08)  Сколько угодно. Фильтр расчитывается лишь в том случае, если переменная flag == 1. Она устанавливается в 1 в функции обработки прерывания от АЦП, и сбрасывается в 0, как только завершился код фильтра для данного отсчёта поступившего с АЦП. После этого фильтр не считается, а моргают лампочки.... Представьте, что одна итерация "мигания" длится 1 секунду. Это значит, что фильтр может обновляться не чаще, чем 1 раз в секунду. Цитата(Грендайзер @ Aug 5 2015, 20:08)  Впрочем я в ф-ции int main(void) я коментил лампочки и писал строчку типа Код dout = din; без всякого фильтра. Всё равно никакого эффекта. Как будто компилятор хочет всё выполнять в функциях прерывания, а на основную ему наср наплевать  При том самое интересное, что в основной ф-ции переменную flag процессор обнуляет, а вот фильтр банит... Довольно бессмысленно вносить случайные изменения в неработающую программу в надежде, что она заработает. И выкиньте из головы мысль о том, что компилятор виноват. Это ошибки в вашей программе. Да, для оптимизации компилятору разрешено многое такое, что новичка может поставить в тупик, но есть чёткие правила. Если хотите понимать, что он нагенерил, смотрите в справочник инструкций процессора. Начинайте с низких уровней оптимизации, потому что на высших уровнях код корёжится до неузнаваемости, без поллитры не разберёшься, но при этом правильные программы не ломаются. Ну и вообще сомневаюсь, что у вас всё упёрлось в оптимизацию. Выглядит так, будто вы просто не понимаете, как работает программа, и надеетесь включением оптимизации волшебным образом решить все проблемы. Можно было бы попробовать поразбираться, но вы привели неполный код, а полный, наверное, слишком большой, то есть разбираться будет лень. Ну и я не знаю, как там в SAMах всё работает, может быть, хитрые нюансы есть.
|
|
|
|
|
Aug 5 2015, 18:01
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Представьте, что одна итерация "мигания" длится 1 секунду Не могу представить. Процессору пришло прерывание, он на эту итерацию плюнул и пошёл отрабатывать прерывание. Цитата Довольно бессмысленно вносить случайные изменения в неработающую программу в надежде, что она заработает. Изменения не случайные, они показывают, что в целом ход программы идёт так как задумано... не монятно куда пропадают отдельные куски... вот тут да... Впрочем что ещё может быть, если даже из ассемблерного кода этот самый кусок пропал? P.S. Впрочем, может Вы в чём то и правы... Попробую ещё раз всё с самого насала написать.
Сообщение отредактировал Грендайзер - Aug 5 2015, 18:03
|
|
|
|
|
Aug 7 2015, 12:13
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Снова здравствуйте. Вообщем промучился ещё день но так и не пришёл к решению. Вопрос к гуру ARMов, правильно ли в моём коде происходит уход в прерывание. Написал простейшую программулину, которая генерит пилу на выходе ЦАП. Заметил интересную особенность когда просматривал дизасемблированный код. В одном из регистров (r3), действительно появляются значения пилы в процессе работы цикла в программе main. Однако при уходе в подпрограмму прерывания в него записывается какая то ерунда. В ЦАП же записывается содержимое регистра r2 в котором, в процессе основного цикла хранится значение размаха пилы, т.е. 3000, а при входе в подпрограмму прерывания в него записывается значением которым я инициировал переменную dout, т.е. 300. После же выхода из прерывания в регистр r3 возвращается значение dout на момент когда пришло прерывание, а в r2 3000, т.е. размах пилы. Приведу весь код и рисунки с дизассемблера. CODE #include "sam.h"
int dout = 300;
void DACC_Handler( void );
int main(void) { /* Initialize the SAM system */ SystemInit();
__enable_irq (); // --------------- Enable Interrupts in NVIC ---------------------------- NVIC_EnableIRQ(DACC_IRQn); //------------------- Disable Watchdog Timer --------------------------- WDT -> WDT_MR = WDT_MR_WDDIS; // disable Watchdog Timer //----------------------------------------------------------------------
//----------------- Switch to fast RC oscillator ---------------------- // Enable Fast RC oscillator but DO NOT switch to RC now PMC-> CKGR_MOR |= (CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCEN);
// Wait the Fast RC to stabilize while (!(PMC -> PMC_SR & PMC_SR_MOSCRCS)){};
// Change Fast RC oscillator frequency PMC-> CKGR_MOR = (PMC-> CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) | CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCF_4_MHz;
// Wait the Fast RC to stabilize while (!(PMC-> PMC_SR & PMC_SR_MOSCRCS)){};
// Switch to Fast RC PMC-> CKGR_MOR = (PMC -> CKGR_MOR & ~CKGR_MOR_MOSCSEL) | CKGR_MOR_KEY_PASSWD; //---------------------------------------------------------------------------------------------------------------
//-------------------------- Switch to Main Clock --------------------------------------------------------------- // Switch to Main Clock PMC -> PMC_MCKR |= PMC_MCKR_CSS_MAIN_CLK;
// Wait the Fast RC to stabilize while (!(PMC-> PMC_SR & PMC_SR_MOSCRCS)){}; //---------------------------------------------------------------------------------------------------------------
//-------------------------- PLLA enable ------------------------------------------------------------------------
// Number Wait States Required to Access the Embedded Flash Memory (page 366 and 1183 datasheet) EFC0 -> EEFC_FMR = (EFC0 -> EEFC_FMR & ~EEFC_FMR_FWS_Msk) | EEFC_FMR_FWS(6);
// Always stop PLL first! PMC-> CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_MULA(0);
// Adjustment of the Multiplier and Divider PMC-> CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_MULA(24) | CKGR_PLLAR_DIVA(1) | CKGR_PLLAR_PLLACOUNT(100) | PMC_MCKR_PLLADIV2;
// Wait the PLL Lock while (!(PMC-> PMC_SR & PMC_SR_LOCKA)){};
// Switch to PLLA Clock PMC -> PMC_MCKR = (PMC -> PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_PLLA_CLK;
// Wait Master Clock is Ready while(!(PMC -> PMC_SR & PMC_SR_MCKRDY)){}; // --------- Enables the corresponding peripheral clock ---------------- // ------------------------ Enable PIOA -------------------------------- PMC -> PMC_PCER0 = (1 << ID_PIOA); // ---------------------- Enable DACC clock ---------------------------- PMC -> PMC_PCER0 = (1 << ID_DACC); PMC -> PMC_PCER0 = (1 << ID_ADC);
// --------- Enable corresponding pins --------------------------------- PIOA -> PIO_PER = PIO_PER_P19 | PIO_PER_P20; // ---- Enable output corresponding pins in PORTA----------------------- PIOA -> PIO_OER = PIO_OER_P19|PIO_OER_P20; // -- DAC SET // --------------------- DACC Software Reset --------------------------- DACC -> DACC_CR = DACC_CR_SWRST; // ----------------------- DACC Mode Register -------------------------- DACC -> DACC_MR = DACC_MR_WORD_HALF | DACC_MR_USER_SEL_CHANNEL1;
// ----------------------- Channel 1 Enable ---------------------------- DACC -> DACC_CHER = DACC_CHER_CH1;
// ------------------- End of conversion interrupt --------------------- DACC -> DACC_IER = DACC_IER_TXRDY;
// ---------------------- Start of conversion -------------------------- //DACC -> DACC_CDR = DACC_CDR_DATA(dout);
while (1) { if (dout == 3000) {dout = 0;} else {dout = dout + 100;} } return 0; }
void DACC_Handler( void ) { volatile int IRQ_sense = 0; IRQ_sense = DACC -> DACC_ISR; DACC -> DACC_CDR = DACC_CDR_DATA(dout); return; }
Сообщение отредактировал IgorKossak - Aug 7 2015, 16:09
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Эскизы прикрепленных изображений
|
|
|
|
|
Aug 7 2015, 13:20
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Ну началось... Бог с ней с пилой... Мне не важно, что там будит формироваться, мне важно что б там хоть что то формироалось. Я пробовал обнулять в основной программе номера элементов буфера. Т.е. так Код while (1) { if (n == 8) {n = 0;} } return 0; }
void DACC_Handler( void ) { volatile int IRQ_sense = 0; IRQ_sense = DACC -> DACC_ISR; DACC -> DACC_CDR = DACC_CDR_DATA(dout[n]); n = n + 1; return; } Так вот команда "n + 1" исправно выполняется, а вот обнуление в цикле "while(1)" т.е. "n = 0" не происходит. Почему? Может кто нибудь предложить программку, что б данные из "main" передать в "void DACC_Handler( void )"? P.S. int dout[8] = {300, 800, 1300, 1800, 2300, 2800, 3200, 100};
Сообщение отредактировал Грендайзер - Aug 7 2015, 13:24
|
|
|
|
|
Aug 7 2015, 13:31
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (Грендайзер @ Aug 7 2015, 16:20)  а вот обнуление в цикле "while(1)" т.е. "n = 0" не происходит. Ну почему-же не происходит? Иногда может быть и происходит - как звезды на небе станут. Что написали, то и получили - два асинхронных процесса что-то делают с одной переменной. QUOTE Может кто нибудь предложить программку, что б данные из "main" передать в "void DACC_Handler( void )"? Вы свое 'n' и 'dout' как-бы передаете, только делаете с ним хрен знает что. Повторяю - думайте над АЛГОРИТМОМ. Над его реализацией будете думать ПОТОМ. while (1)for(;; ) { if (n == 8) {n = 0;} } void DACC_Handler( void ) { volatile int IRQ_sense = 0; IRQ_sense = DACC -> DACC_ISR; // (полагаю, что дефайн для DACC структуры писал не индийский недоучка и не Грендайзер) DACC -> DACC_CDR = DACC_CDR_DATA( dout[n] ); n = n + 1; if( ++n > 7 ) n = 0; return; }
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Aug 7 2015, 13:39
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Вы свое 'n' и 'dout' как-бы передаете, только делаете с ним хрен знает что Частота работы ядра - 100 МГц, частота работы ЦАП - 50 МГц, прерывание возникает не ратьше чем в 25 циклов ЦАП. Ядро какбэ успеет ещё до Камчатки пешком дойти, пока процесс чухнётся. Такая программа и без for(;;) нормально работает. Как n в main передать?
Сообщение отредактировал Грендайзер - Aug 7 2015, 13:45
|
|
|
|
|
Aug 7 2015, 13:47
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Ну тогда так: не забыли приписать volatile к переменной n? Нет, не забыл! Volatile куда тока не писал....
|
|
|
|
|
Aug 7 2015, 13:51
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (Грендайзер @ Aug 7 2015, 16:39)  Частота работы ядра - 100 МГц, частота работы ЦАП - 50 МГц, прерывание возникает не ратьше чем в 25 циклов ЦАП. Ядро какбэ успеет ещё до Камчатки пешком дойти, пока процесс чухнётся. Написаное Вами Выше ни о чем, кроме каши в голове не свидетельствует, что было ясно и раньше  . Абсолютное непонимание того, что сотворили. Читайте по буквам еще раз - "два асинхронных процесса что-то делают с одной переменной". QUOTE Такая программа и без for(;;) нормально работает. Писать ГРАМОТНО нужно даже если "работает".
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Aug 7 2015, 13:55
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (Грендайзер @ Aug 7 2015, 16:47)  Нет, не забыл! Volatile куда тока не писал.... Можете еще и в бубен постучать, свечку поставить. Только все работает у Вас правильно, в том смысле, как НАПИСАЛИ, так и "работает".
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Aug 7 2015, 14:11
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Что на выходе получиться должно-то? Должно получится обнуление переменной n в цикле "while(1)" функции main. Цитата как НАПИСАЛИ, так и "работает". Так подскажите, как написать, что б без бубна и свечек...
|
|
|
|
|
Aug 7 2015, 14:20
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Легко. Запретить прерывания на время проверки и обнуления переменной. Честно говоря звучит... странновато... но попробую! К сожалению плата на работе, так что придётся до пн. потерпеть. Цитата Только зачем всё это? Что мешает обнулять в обработчике прерывания? Проблема в том, что у меня почему то не передаются даннные из main в подпрограмму прерывания. Обнулить n кончно можно и в обработчике, но вот если мне надо какой нить хитрый фильтр посчитать... Эдак я пока из обработчика выйду столько событий могу напропускать... Да и насколько я понимаю, прерывания не для того, что б в них что то считать, они лишь нужны для общения с переферией. Цитата не каждый раз оно сможет занулить эту переменную, даже если цикл успевает крутиться между прерываниями. Может, это вас и подкосило Не вижу корелляции если честно... На том всё и основано...
Сообщение отредактировал Грендайзер - Aug 7 2015, 14:30
|
|
|
|
|
Aug 7 2015, 15:46
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Грендайзер @ Aug 7 2015, 17:20)  Проблема в том, что у меня почему то не передаются даннные из main в подпрограмму прерывания. Всё передаётся. Просто передаётся оно не так, как вам кажется, а так, как написано в исходнике. То есть проблема в том, что ваше видение программы и её поведение в соответствии с исходником отличаются. Надо что-то подправить в консерватории Цитата(Грендайзер @ Aug 7 2015, 17:20)  Да и насколько я понимаю, прерывания не для того, что б в них что то считать, они лишь нужны для общения с переферией. Это предрассудок. В общем случае обычно так оно и есть, но здравый смысл никто не отменял, и часто оправданно отклонение от этого правила. Цитата(Грендайзер @ Aug 7 2015, 17:20)  Обнулить n кончно можно и в обработчике, но вот если мне надо какой нить хитрый фильтр посчитать... Эдак я пока из обработчика выйду столько событий могу напропускать... Насколько я могу судить, затягивание обработки прерывания АЦП может привести к отложенной обработке прерывания ЦАР. А это, в свою очередь, может привести к чрезмерному джиттеру на выходе ЦАП (а может и не привести). Есть простое решение: дать прерыванию ЦАП более высокий приоритет.
|
|
|
|
|
Aug 10 2015, 05:51
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Цитата Пардон, но вам до такого понимания как пешком до Луны Ну видимо не мне одному... колдунство с отключением прерывания не сработало
|
|
|
|
|
Aug 10 2015, 07:14
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Вылезает. При выходе из прерывания, я его отключаю. Тут дрогой интересный момент. Как я понял, некоторое время контроллер работает нормально, в ходе пошаговой отладки (с отключённым прерыванием) процессор некоторое время работает нормально, а потом вылетает в пустой цикл в функции Код void Dummy_Handler(void) { while (1) { } } как будто поступило прерывание, обработчик для которого не указан. Хотя никаких других прерываний я не включал. Ничего не менял кроме программы внутри main и в обработчике. По традиуии приведу код. Код while (1) { if(n == 7) {n = 0;} if(DACC -> DACC_IMR == 0) // если прерывание отключено {DACC -> DACC_IER = DACC_IER_TXRDY;} // включить прерывание } return 0; }
void DACC_Handler( void ) { DACC -> DACC_ISR; DACC -> DACC_CDR = DACC_CDR_DATA(dout[n]); n = n + 1; DACC -> DACC_IDR = DACC_IDR_TXRDY; // отключить прерывание return; } P.S. Цитата 25 циклов на 50 МГц - это 50 циклов на 100 МГц 25 циклов на 50 это 25 циклов на 50. Частота работы ЦАП 50МГц
Сообщение отредактировал Грендайзер - Aug 10 2015, 07:17
|
|
|
|
|
Aug 11 2015, 11:38
|
Местный
  
Группа: Участник
Сообщений: 368
Регистрация: 18-04-11
Из: Город-герой Москва
Пользователь №: 64 451

|
Ну сейчас меня с гавн съедят, и всё же... Товарищ scifi Вы где? Вы были правы! Правда так я и не допетрил кой чего, а именно... Следующий код обработчика прерывания, как я уже писал результата не даёт: Код void DACC_Handler( void ) { DACC -> DACC_ISR; // читаем регистр что бы сбросить флаг прерывания DACC -> DACC_CDR = DACC_CDR_DATA(dout[n]); //передаём данные в в цап {n = n + 1;} // увеличиваем индекс элемента массива DACC -> DACC_IDR = DACC_IDR_TXRDY; // отключаем прерывание в переферии return; } не зависимо от того какая строчка "n = n + 1" или "DACC -> DACC_CDR = DACC_CDR_DATA(dout[n]);" идёт раньше. Но стоит одну из этих строк (или их обе - не важно) поставить после строки "DACC -> DACC_IDR = DACC_IDR_TXRDY;" как всё чудным образом начинает работать. Т.е. Код void DACC_Handler( void ) { DACC -> DACC_ISR; DACC -> DACC_IDR = DACC_IDR_TXRDY; [u]DACC -> DACC_CDR = DACC_CDR_DATA(dout[n]);[/u] [u]{n = n + 1;}[/u] return; } или Код DACC -> DACC_ISR; [u]{n = n + 1;}[/u] DACC -> DACC_IDR = DACC_IDR_TXRDY; [u]DACC -> DACC_CDR = DACC_CDR_DATA(dout[n]);[/u] return; или Код DACC -> DACC_ISR; [u]DACC -> DACC_CDR = DACC_CDR_DATA(dout[n]);[/u] DACC -> DACC_IDR = DACC_IDR_TXRDY; [u]{n = n + 1;}[/u] return; Из - за чего это происходит?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|