Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ARM. Энкодеры и акселерометры
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3, 4
Zliva
Всем привет!
Нужна помощь.
Есть виброплощадка с двумя дебалансными валами, с одной стороны которой через эластические муфты приделаны двигатели, а с другой – инкрементные энкодеры. Площадка крепится через пружины к станине. Двигатели прикручены к станине жестко. Валы площадки не синхронизированы. К площадке крепится датчик ускорения ADXL210 с выходным сигналом ШИМ. Двигатель вращается с частотой 1500 об/мин, следовательно это равно 25об/сек. Энкодер имеет разрешение 1024им/об, это равно 1024*25=25600Гц. Начальное положение определяться перед пуском. Поскольку дебалансный вал имеет эксцентриситет, то соответственно он направлен в низ. Это и есть его начальное положение. Контролер и комп НЕ УПРАВЛЯЕТ ДВИГАТЕЛЯМИ, а они запускаются отдельно через рубильник.
Точность измерения:
  • угловое положение +/-0,4градуса;
  • угловую скорость(+/-1.0град/сек);
  • угловое ускорение (после интерполяции графика скорости. Зависит от метода);
  • линейное ускорение(+/-0,1g);

Нужно периодично опрашивать датчики, чтобы знать его положение, ускорение в каждый момент времени. Данные через USB от датчиков должны заливаться на комп.

Нужно измерять положения дебалансных валов и их скорость, ускорение, а также ускорение, скорость, положение площадки. Ловить сдвиг фаз между положениями валов.

Здесь нимного обсуждалось и здесь
Что уже есть: изготовлена площадка, на ней стоят энкодеры. Уже запускал, работает.
Прикупил ARM отладочную плату AT91SAM7S64_DBoard для ARM микроконтроллеров фирмы ATMEL и программатор J-Link - USB JTAG adapter. Хочу на базе этого дивайса решить эту задачу. Опит программирования только AVR. Знаю немного Си и Delphi. Очень нужно. Помогите пожалуйста.
_Pasha
Я бы все-таки энкодеры обрабатывал простеньким AVR Tiny2313, результаты отдавал по SPI, с согласованием питания.
Zliva
Цитата(_Pasha @ Jul 30 2009, 11:17) *
Я бы все-таки энкодеры обрабатывал простеньким AVR Tiny2313, результаты отдавал по SPI, с согласованием питания.

Зачем городить схему. В принципе ARM может работать с напряжением 5В, но только на вход. Так написано в даташите. Я думаю все равно ставить оптронную развязку. Хочу задействовать прерывания для обработки сигналов. Для начала помогите сконфигурировать IAR с JTAG-м. Хочу залить первую программу, какую не будь мигалку. Нажал кнопку и светится, отпустил - погасло.
Zliva
С программированием ARM разобрался. Программируется AT91SAM7S128 и через J-LINK и через SAM-BA. Перешел с IAR на KEIL. Мне нравится. Отличный там симулятор.
Возникло несколько вопросов.
1. Объясните пожалуйста на пальцах разницу между CDC, HID,MSD и USB SER.SYS?
2. Где можно про это почитать?
3. Какой вариант в моем случае лучше?

Хочу для сначала измерить положение вала. Думаю делать так (набросайте помидорами сразу):
Задействую первое прерывание на линию А энкодера, а второе - В на обычный вход(используется для определения направления вращения). Сохраняю значение текущего положения постоянно. В момент возникновения прерывания сохраняю текущее значение времени. Время отсчитывается с момента старта. Затем формирую пакет «Время» - «Текущая позиция» «количество оборотов» (пакет буде побольше включая скорость для двух энкодеров и ускорение для двух координат) и по запросу с ПК считываю значение. На ПК интерполирую данные, а затем дифференцирую или интегрирую и получаю остальные характеристики. Вот коротко что хочу. Может у кого-то будут какие-то другие идеи по решению этой задачи, буду рад. Поскольку начинаю юзать АРМ, могут возникнуть вопросы. Надеюсь на вашу помощь.

4. Может у кого-то есть рабочий пример по работе с USB?
aaarrr
1. Первые три - классы устройств USB; usbser.sys - драйвер винды, обслуживающий CDC ACM.
2. usb.org
3. Зависит от Вашей задачи - какой поток, требуется ли гарантированная доставка данных и т.д. и т.п. Стандартными классами пользоваться вовсе не обязательно.
Zliva
Цитата(aaarrr @ Aug 15 2009, 23:36) *
3. Зависит от Вашей задачи - какой поток, требуется ли гарантированная доставка данных и т.д. и т.п. Стандартными классами пользоваться вовсе не обязательно.

Гарантия доставки обязательна. Со стороны компа буду периодично считывать данные.
Тогда какой класс выбрать?
aaarrr
Если гарантия доставки обязательна, то в качестве типа передачи нужно выбирать bulk. Так какой поток нужен?
И лучше почитайте с начала об USB вообще.
Zliva
Цитата(aaarrr @ Aug 15 2009, 23:52) *
Если гарантия доставки обязательна, то в качестве типа передачи нужно выбирать bulk. Так какой поток нужен?
И лучше почитайте с начала об USB вообще.

Спасибо. Разберусь обязательно. Если была бы еще русскоязычная документация, было бы попроще. Ну нечего. Прорвусь. А скорость опроса примерно 1кГц(если вы это имели в виду).
aaarrr
Цитата(Zliva @ Aug 16 2009, 00:57) *
А скорость опроса примерно 1кГц(если вы это имели в виду).

Нет, я имел в виду именно поток. Тот же CDC со стандартным виндовым драйвером имеет ограничения - не получится отправить хосту более одного пакета за миллисекунду (т.е. предельная скорость составит 64000 байт/с), в обратном направлении таких ограничений нет.
Zliva
Цитата(aaarrr @ Aug 16 2009, 00:01) *
Нет, я имел в виду именно поток. Тот же CDC со стандартным виндовым драйвером имеет ограничения - не получится отправить хосту более одного пакета за миллисекунду (т.е. предельная скорость составит 64000 байт/с), в обратном направлении таких ограничений нет.

Что-то я запутался. Нужно немного почитать чтобы говорить на вашем языке. Правильно ли я понял:
У меня есть пакет.
«Время»___«Текущая позиция»___«к-во обо-в»___«Текущая позиция»___«к-во обо-в»___Ускорение Х___Ускорение Y
__________Энкодер 1___________Энкодер 1______Энкодер 2__________Энкодер 2
_8байт_____2байта______________12 байт________2байта______________12 байт________2байта________2 байта

Его размер будет 40байта. Если я хочу опрашивать устройство с частотой 1кГц, то получается 40кБайт/с.
Так какой класс выбрать?
aaarrr
Цитата(Zliva @ Aug 16 2009, 01:30) *
Так какой класс выбрать?

Оставьте пока классы и почитайте об организации передачи данных в USB на более низком уровне.

P.S. В вашем случае с одинаковым успехом можно использовать CDC или вообще не пользоваться стандартными классами.
Zliva
Цитата(aaarrr @ Aug 16 2009, 00:39) *
Оставьте пока классы и почитайте об организации передачи данных в USB на более низком уровне.

P.S. В вашем случае с одинаковым успехом можно использовать CDC или вообще не пользоваться стандартными классами.

Спасибо. Но а если я с хочу считывать данные со скоростью не 1кГц, а скажем 5кГц – это возможно?
aaarrr
Возможно. Другое дело, что фрейм USB равен 1 мс, поэтому на низкую латентность при работе рассчитывать не приходится.
Zliva
Вот код обработки по прерыванию положения первого энкодера.
CODE
#include <AT91SAM7S128.H> /* AT91SAM7S64 definitions */
#include "..\Board.h"

volatile unsigned int ENCODER1_Position = 0; /* Текуща позиция энкодера 1*/
volatile unsigned long int ENCODER1_Count = 0; /* Текуща позиция энкодера 1*/
#define ENCODER1_A_MASK (1<<20) /* PA19 */
#define ENCODER1_B_MASK (1<<19) /* PA20 */
#define ENCODER2_A_MASK (1<<15) /* PA15 */
#define ENCODER2_B_MASK (1<<14) /* PA14 */
#define ENCODER_A_MASK (ENCODER1_A_MASK|ENCODER1_B_MASK|ENCODER2_A_MASK|ENCODER2_B_MASK)

#define ENCODER1_A (1<<20) // PA19
#define ENCODER1_B (1<<19) // PA20
#define ENCODER2_A (1<<15) // PA15
#define ENCODER2_B (1<<14) // PA14


#define ENCODER1_resolution 1024
#define ENCODER2_resolution 1024


extern AT91S_PIO * pPIO; /* Global Pointer to PIO */

extern __irq void irq0_int (void); /* IRQ0 Function */


void irq0_nint (void) { /* Nested IRQ0 (Push button SW2) */

if ((pPIO->PIO_PDSR & ENCODER1_A) == 0) { /* Проверяем активный уровень на входе А энкодера 1*/
if ((pPIO->PIO_PDSR & ENCODER1_B) == 0) { /* Определяем направление вращения энкодера 1*/
if (ENCODER1_Position == (ENCODER1_resolution-1)) {/*Проверяем не прывисл ли
ENCODER1_Position значения полосок на энкодере*/
ENCODER1_Position = 0;/*Если превысил то отсчитываем с 0*/
// ENCODER1_Count++; /*Увеличиваем на 1 значения оборотов */
}
ENCODER1_Position++;} /* Если за часовой стрелкой то увеличиваем на 1*/
else {
if (ENCODER1_Position == 0) { /* Проверяем не прывисл ли ENCODER1_Position значения 0*/
ENCODER1_Position = (ENCODER1_resolution-1);/*Если 0 то отсчитываем с ENCODER1_resolution-1*/
ENCODER1_Count++; /*Уменьшаем на 1 значения оборотов */
}
ENCODER1_Position--; } /* Если против часовой стрелкой то уменьшаем на 1*/
}

*AT91C_AIC_EOICR = 0; /* End of Interrupt*/
}


void init_extint (void) { /* Setup IRQ 0 Interrupt */
AT91S_AIC * pAIC = AT91C_BASE_AIC; /* Setup IRQ0 Interrupt Mode and Vector with Priority 0 and Enable it */
/*
AIC_SMR - Регистр источника прерывания 0
AT91C_ID_IRQ0 - ID Прерывание для IRQ0
AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE - Internal Sources Code Label Positive
Edge triggered - Положительный фронт */
pAIC->AIC_SMR[AT91C_ID_IRQ0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | 0;// AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE
/* Вектор прерывания. AIC_SVR0..AIC_SVR31 - В эти регистры записываются
адреса соответствующих процедур обработки прерывания для каждого источника.*/
pAIC->AIC_SVR[AT91C_ID_IRQ0] = (unsigned long) irq0_int; /*Регистр разрешения прерываний*/
pAIC->AIC_IECR = (1 << AT91C_ID_IRQ0);
}

Вроде все правильно, но почему дважды вызывается прерывание? Все значения пересылаю через USART.
CODE
#include <AT91SAM7S128.H> /* AT91SAM7S64 definitions */
#include "..\Board.h"

#define BR 115200 /* Baud Rate */

#define BRD (MCK/16/BR) /* Baud Rate Divisor */


AT91S_USART * pUSART = AT91C_BASE_US0; /* Global Pointer to USART0 */


void init_serial (void) { /* Initialize Serial Interface */

*AT91C_PIOA_PDR = AT91C_PA5_RXD0 | /* Enable RxD0 Pin */
AT91C_PA6_TXD0; /* Enalbe TxD0 Pin */

pUSART->US_CR = AT91C_US_RSTRX | /* Reset Receiver */
AT91C_US_RSTTX | /* Reset Transmitter */
AT91C_US_RXDIS | /* Receiver Disable */
AT91C_US_TXDIS; /* Transmitter Disable */

pUSART->US_MR = AT91C_US_USMODE_NORMAL | /* Normal Mode */
AT91C_US_CLKS_CLOCK | /* Clock = MCK */
AT91C_US_CHRL_8_BITS | /* 8-bit Data */
AT91C_US_PAR_NONE | /* No Parity */
AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */

pUSART->US_BRGR = BRD; /* Baud Rate Divisor */

pUSART->US_CR = AT91C_US_RXEN | /* Receiver Enable */
AT91C_US_TXEN; /* Transmitter Enable */
}


int sendchar (int ch) { /* Write character to Serial Port */

if (ch == '\n') { /* Check for CR */
while (!(pUSART->US_CSR & AT91C_US_TXRDY)); /* Wait for Empty Tx Buffer */
pUSART->US_THR = '\r'; /* Output CR */
}
while (!(pUSART->US_CSR & AT91C_US_TXRDY)); /* Wait for Empty Tx Buffer */
return (pUSART->US_THR = ch); /* Transmit Character */
}


int getkey (void) { /* Read character from Serial Port */

while (!(pUSART->US_CSR & AT91C_US_RXRDY)); /* Wait for Full Rx Buffer */
return (pUSART->US_RHR); /* Read Character */
}

Вот шапка.
CODE
AREA IRQ0, CODE, READONLY
ARM

PRESERVE8
ALIGN
IMPORT irq0_nint
EXPORT irq0_int
irq0_int FUNCTION

SUB LR, LR, #4 ; Update Link Register
STMFD SP!, {R0-R12, LR} ; Save Workspace & LR to Stack
MRS R0, SPSR ; Copy SPSR to R0
STMFD SP!, {R0, R1} ; Save SPSR to Stack (8-byte)
MSR CPSR_c, #0x1F ; Enable IRQ (Sys Mode)
STMFD SP!, {R0, LR} ; Save LR_sys to Stack (8-byte)
LDR R0, =irq0_nint ; Get IRQ Function Address
MOV LR, PC ; Return Address
BX R0 ; Call IRQ Function
LDMFD SP!, {R0, LR} ; Restore LR_sys
MSR CPSR_c, #0x92 ; Disable IRQ (IRQ Mode)
LDMFD SP!, {R0, R1} ; Restore SPSR to R0
MSR SPSR_cxsf, R0 ; Copy R0 to SPSR
LDMFD SP!, {R0-R12, PC}^ ; Return to program

ENDFUNC

END


Модератор. Zliva, в следующий раз буду просто удалять такие цитаты из сообщения. Либо форматируйте их сами, оформляя тэгами [ codebox ] и урезая по ширине, либо прилагайте к сообщению в виде текстовых файлов, как это рекомендуют Правила форума.
С уважением, rezident.
aaarrr
Цитата(Zliva @ Aug 23 2009, 19:35) *
Код
        /* Setup IRQ0 Interrupt Mode and Vector with Priority 0 and Enable it */
          /*
          AIC_SMR        -    Регистр источника прерывания 0
          AT91C_ID_IRQ0 -    ID Прерывание для IRQ0
          AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE    -     Internal Sources Code Label Positive
                                                  Edge triggered - Положительный фронт
          */
  pAIC->AIC_SMR[AT91C_ID_IRQ0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | 0;            //     AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE

Прерывание от IRQ0 является внешним источником, поэтому обратите внимание на такие строки в хидере:
Цитата
#define AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE ((unsigned int) 0x1 << 5) // (AIC) Internal Sources Code Label Positive Edge triggered
#define AT91C_AIC_SRCTYPE_EXT_NEGATIVE_EDGE ((unsigned int) 0x1 << 5) // (AIC) External Sources Code Label Negative Edge triggered


Цитата(Zliva @ Aug 23 2009, 19:35) *
Вроде все правильно, но почему дважды вызывается прерывание? Все значения пересылаю через USART.

А откуда это видно?

Цитата(Zliva @ Aug 23 2009, 19:35) *
Вот шапка.

Шапка с безобразным оверхедом. Нет никакой необходимости пихать все регистры на стек: R4-R11 и так никто не тронет.
Zliva
Цитата(aaarrr @ Aug 23 2009, 19:11) *
Прерывание от IRQ0 является внешним источником, поэтому обратите внимание на такие строки в хидере:

Вижу в 232analyzer (утилита для работы с ком-портом), что при однократном нажатии кнопки (энкодер лежит с боку, пока не подключал), данные получаю и оны непрерывно поступают, пока кнопка нажата, а я хочу, чтобы происходило прерывание на переходе 0-1. Чем можете помочь? Неужели дребезг?
Манипулою так:
Прерывания от irq0 заведено на кнопку (симулирую линию энкодера А), а РА20 на кнопку B2(симулирую линию энкодера В). При однократном нажатии на B1 значение убывает, но их приходит очень много. Например, один раз нажал получил значение 9 десть раз. При удерживании В2 нажимаю на B1. Значения идут по возрастающей. Количество резолюций поставил 10 только для тестирования. В реальности энкодер имеет 1024 имп/об.

Цитата
А откуда это видно?

Утилита 232analyzer для работы с ком-портом
Цитата
Шапка с безобразным оверхедом. Нет никакой необходимости пихать все регистры на стек: R4-R11 и так никто не тронет.

Тогда как правильно сделать?
aaarrr
Цитата(Zliva @ Aug 23 2009, 22:23) *
Вижу в 232analyzer (утилита для работы с ком-портом), что при однократном нажатии кнопки (энкодер лежит с боку, пока не подключал), данные получаю и оны непрерывно поступают, пока кнопка нажата, а я хочу, чтобы происходило прерывание на переходе 0-1. Чем можете помочь? Неужели дребезг?

А что Вас удивляет? Вполне естественно, что кнопка имеет дребезг.

Цитата(Zliva @ Aug 23 2009, 22:23) *
Утилита 232analyzer для работы с ком-портом

Вы не выложили ту часть кода, которая заведует отравкой данных, поэтому судить о наблюдаемой картине никто не возьмется.

Цитата(Zliva @ Aug 23 2009, 22:23) *
Тогда как правильно сделать?

Очевидно, не сохранять лишнее. Если обработчик написан на 'C' без всяких naked, то строки:
Код
                STMFD   SP!, {R0-R12, LR}    ; Save Workspace & LR to Stack
                ...
                LDMFD   SP!, {R0-R12, PC}^   ; Return to program

можно спокойно заменить на:
Код
                STMFD   SP!, {R0-R3, R12, LR}    ; Save Workspace & LR to Stack
                ...
                LDMFD   SP!, {R0-R3, R12, PC}^   ; Return to program

Но делать это стоит только при ясном понимании, почему так можно. В противном случае оставьте как есть - процедура все равно рабочая.
Zliva
Не могу понять, почему когда я удерживаю кнопку (как бы дребезга недолжно быть), возникает прерывание? Может здесь
pAIC->AIC_SMR[AT91C_ID_IRQ0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE|0 что-то не так? Даже в симуляторе та же фича. Вот весь проект (на базе Hello.Uv2)
aaarrr
Цитата(Zliva @ Aug 23 2009, 23:41) *
Может здесь
pAIC->AIC_SMR[AT91C_ID_IRQ0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE|0 что-то не так? Даже в симуляторе та же фича

Что там не так, я уже написал выше.

Работа с прерываниями по фронту вообще требует предельной внимательности - Вы уверены, что это действительно необходимо?
Zliva
Цитата(aaarrr @ Aug 24 2009, 09:17) *
Что там не так, я уже написал выше.

Работа с прерываниями по фронту вообще требует предельной внимательности - Вы уверены, что это действительно необходимо?

В принципе – да. Уверен. Вы что-то можете предложить другое?
aaarrr
Цитата(Zliva @ Aug 24 2009, 12:15) *
Вы что-то можете предложить другое?

Для обработки энкодеров логично было бы использовать общее прерывание PIO. Выставляется по любому фронту на выводе (-ах), при этом является внутренним источником для AIC'а.
Zliva
Цитата(aaarrr @ Aug 24 2009, 13:37) *
Для обработки энкодеров логично было бы использовать общее прерывание PIO. Выставляется по любому фронту на выводе (-ах), при этом является внутренним источником для AIC'а.

Спасибо, Вам. Если можно, небольшой пример. Может есть смысл задействовать два прерывания на один энкодер?

Кажись настроил прерывание по фронту. Но сейчас появилась следующая проблема. Пропуск шагов(или неверный алгоритм работы). Суть такая (на картинке видно устройство и энкодер), рычаг вала энкодера поворачиваю в какое-то крайнее положение до упора. Затем делаю RESET устройства. Проворачиваю до следующего крайнего положения(до упора). Получаю следующую последовательность:
0 - 637
1020-633
1015-627
1010-622 и т.д.
Что не так?
aaarrr
Цитата(Zliva @ Aug 24 2009, 15:32) *
Если можно, небольшой пример. Может есть смысл задействовать два прерывания на один энкодер?

Пример:
CODE
void pioa_irq_init(void)
{
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOA] = (unsigned int)irq_pioa;
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOA] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | PIOA_IRQ_PRIORITY;
AT91C_BASE_AIC->AIC_IECR = (1UL << AT91C_ID_PIOA);
AT91C_BASE_SYS->PIOA_IER = PINX_MASK | PINY_MASK;
}

__irq void irq_pioa(void)
{
unsigned int status = AT91C_BASE_SYS->PIOA_ISR;
if(status & PINX_MASK)
{
...
}
if(status & PINY_MASK)
{
...
}
AT91C_BASE_AIC->AIC_EOICR = status;
}

Смысла использовать более одного прерывания не вижу - фронты ведь разнесены по времени.

Цитата(Zliva @ Aug 24 2009, 15:32) *
Что не так?

Что-то не очень понятна последовательность. Что такое "1015-627"? Лучше напишите положение вала и насчитанное число для каждой точки.
Zliva
Цитата(aaarrr @ Aug 24 2009, 14:48) *
Что-то не очень понятна последовательность. Что такое "1015-627"? Лучше напишите положение вала и насчитанное число для каждой точки.

Попробую объяснить получше. Суть такая (на картинке видно устройство и энкодер), рычаг вала энкодера поворачиваю в какое-то крайнее положение до упора(соприкосновение двух винтов). Затем делаю RESET устройства (для того, чтобы начать отсчет с нуля). Проворачиваю до следующего крайнего положения рычаг вала энкодера до упора (соприкосновение винта рычага и винта на корпусе энкодера). Затем кручу рычаг в обратную сторону до упора. И так несколько раз. Получаю следующую последовательность в крайних положениях (как изменилось значение положения крайних положениях):
0 - 637
1020-633
1015-627
1010-622 и т.д.
Эта последовательность – им/обр. Так как винты размещены на одной оси с упорными винтами(грубо 180 градусов см.рис.), получается такая последовательность. Энкодер за 1 об. делает 1024 импульса. Надеюсь понятно.
Но куда деваются значения, непонятно. По правильному(я так думаю), должно быть:
0 - 637
637-0
0 - 637
637-0
aaarrr
Ну, если даже направление теряется, то это похоже на косяк в алгоритме. Код приведите.
Zliva
Цитата(aaarrr @ Aug 24 2009, 15:15) *
Ну, если даже направление теряется, то это похоже на косяк в алгоритме. Код приведите.


<Здесь была цитата исходника>.
Удалено модератором (rezident).
aaarrr
Получается, что Вы по заднему фронту сигнала B смотрите сигнал B. Естественно, код все время инкрементируется.
Zliva
Цитата(aaarrr @ Aug 24 2009, 15:49) *
Получается, что Вы по заднему фронту сигнала B смотрите сигнал B. Естественно, код все время инкрементируется.

Тыкните пальцем, слепой. 07.gif
aaarrr
Цитата(Zliva @ Aug 24 2009, 16:56) *
Тыкните пальцем, слепой. 07.gif

Пардон, комментарий вместо кода прочитал:
Код
#define ENCODER1_A             (1<<20) // PA19
#define ENCODER1_B             (1<<19) // PA20

Но все равно проверьте.
И еще: тактирование PIO включить не забыли? Прерывания так будут работать, а из PDSR будут постоянно читаться нули. Очень похоже.

P.S. Пожалуйста, убирайте закомментированные куски из выкладываемого кода.
Zliva
Цитата(aaarrr @ Aug 24 2009, 16:12) *
Пардон, комментарий вместо кода прочитал:
Код
#define ENCODER1_A             (1<<20) // PA19
#define ENCODER1_B             (1<<19) // PA20

Но все равно проверьте.
И еще: тактирование PIO включить не забыли? Прерывания так будут работать, а из PDSR будут постоянно читаться нули. Очень похоже.

В main определил *AT91C_PMC_PCER = (1 << AT91C_ID_PIOA) | (1 << AT91C_ID_IRQ0) | (1 << AT91C_ID_US0);
Пробувал и по AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE
и по AT91C_AIC_SRCTYPE_EXT_NEGATIVE_EDGE ничего. Никаких изменений.
aaarrr
А pPIO правильно проинициализирован?

Пардон, вижу. Лучше так не делать - лишний оверхед по памяти и производительности. Пишите просто AT91C_BASE_PIOA->PIO_PDSR или *AT91C_PIOA_PDSR.
Zliva
Решил сделать просто:
Код
void irq0_nint (void) {
if ((pPIO->PIO_PDSR & ENCODER1_B) == 0) {
        ENCODER1_Position++;}
    else {      ENCODER1_Position--; }
*AT91C_AIC_EOICR = 0;
AT91C_BASE_PIOA->PIO_ISR;}

и посмотреть, что получилось. Так вот.
Цитата(Zliva @ Aug 24 2009, 15:09) *
.....рычаг вала энкодера поворачиваю в какое-то крайнее положение до упора(соприкосновение двух винтов). Затем делаю RESET устройства (для того, чтобы начать отсчет с нуля). Проворачиваю до следующего крайнего положения рычаг вала энкодера до упора (соприкосновение винта рычага и винта на корпусе энкодера). Затем кручу рычаг в обратную сторону до упора. И так несколько раз. Получаю следующую последовательность в крайних положениях (как изменилось значение положения крайних положениях):

0-205->{Вращаю влево}
205-1->{Вращаю вправо}
1-206->{Вращаю влево}
206-2->{Вращаю вправо}
2-207 ->{Вращаю влево}
207-3->{Вращаю вправо}
3-208->{Вращаю влево}
и т.д.
Значение постоянно смещается на 205. Где грабли непойму.
Zliva
Проанализировав все выше упомянутое, склоняюсь к мысли задействовать прерывания по двум каналам. Так как от смещения фазы не уйти.
Прав ли я?
Кто имеет алгоритм для обработки сигналов инкрементирующего энкодера с использованием маркера?

p.s. aaarrr, огромное человеческое СПАСИБО за помощь.
aaarrr
Цитата(Zliva @ Aug 24 2009, 20:20) *
Проанализировав все выше упомянутое, склоняюсь к мысли задействовать прерывания по двум каналам. Так как от смещения фазы не уйти.

Так и задействуйте общее прерывание PIO - так Вы будете получать прерывание на каждый фронт каждого сигнала.
Zliva
Цитата(aaarrr @ Aug 24 2009, 19:35) *
Так и задействуйте общее прерывание PIO - так Вы будете получать прерывание на каждый фронт каждого сигнала.

Это меня устраивает. Помогите пожалуйста сконфигурировать стартап irq_pioa.s для прерывания irq_pioa с использованием Ваших функций, которые Вы приводили немного выше.
И кстати, переменную PIOA_IRQ_PRIORITY Вы как определили?
aaarrr
Цитата(Zliva @ Aug 24 2009, 22:17) *
Это меня устраивает. Помогите пожалуйста сконфигурировать стартап irq_pioa.s для прерывания irq_pioa с использованием Ваших функций, которые Вы приводили немного выше.

Не совсем понял, в чем состоит вопрос. Просто уберите модификатор __irq для использования с вложенными вызовами.

Цитата(Zliva @ Aug 24 2009, 22:17) *
И кстати, переменную PIOA_IRQ_PRIORITY Вы как определили?

Это просто макрос.
Код
#define    PIOA_IRQ_PRIORITY    7
Zliva
Цитата(aaarrr @ Aug 24 2009, 22:23) *
Это просто макрос.
Код
#define    PIOA_IRQ_PRIORITY    7

Спасибо.
Цитата
Не совсем понял, в чем состоит вопрос. Просто уберите модификатор __irq для использования с вложенными вызовами.

Есть у меня файл с названием IRQ0.s. Там прописано
Код
                AREA    IRQ0, CODE, READONLY
                ARM
                PRESERVE8
                ALIGN
                IMPORT  irq0_nint
                EXPORT  irq0_int
irq0_int        FUNCTION
               SUB     LR, LR, #4            
                  STMFD   SP!, {R0-R3, R12, LR}
    MRS     R0, SPSR
               STMFD   SP!, {R0, R1}          
               MSR     CPSR_c, #0x1F        
               STMFD   SP!, {R0, LR}          
               LDR     R0, =irq0_nint        
               MOV     LR, PC
               BX      R0
               LDMFD   SP!, {R0, LR}          
               MSR     CPSR_c, #0x92          
               LDMFD   SP!, {R0, R1}          
               MSR     SPSR_cxsf, R0          
    LDMFD   SP!, {R0-R3, R12, PC}^  ;
               ENDFUNC
               END
Как сюда влепить для PIOA прерывания. Или я с терминологией путаюсь?
aaarrr
Цитата(Zliva @ Aug 24 2009, 23:34) *
Как сюда влепить для PIOA прерывания. Или я с терминологией путаюсь?

Это же просто универсальная обертка. Переименуйте irq0_nint и irq0_int, если хотите, и все.
Zliva
Цитата(aaarrr @ Aug 24 2009, 22:37) *
Это же просто универсальная обертка. Переименуйте irq0_nint и irq0_int, если хотите, и все.

Ничего не получается с прерыванием от PIOA. Все сделал как Вы говорили – НИЧЕГО. Что-то виснет микроконтроллер. Когда комментирую pioa_irq_init() все работает (прерывания не работают), лампочки дрыгаются. Вложу исподники. Посмотрите пожалуйста.
aaarrr
Дык __irq уберите.
Zliva
Цитата(aaarrr @ Aug 24 2009, 23:29) *
Дык __irq уберите.

Убрал. Все равно висим. В симуляторе вроде ОК.
aaarrr
Цитата(Zliva @ Aug 25 2009, 00:35) *
Убрал. Все равно висим. В симуляторе вроде ОК.

AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE - здесь фронт уже не нужен, т.е. вреден. Фронты отловит контроллер PIO.
Zliva
Цитата(aaarrr @ Aug 24 2009, 23:53) *
AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE - здесь фронт уже не нужен, т.е. вреден. Фронты отловит контроллер PIO.

Все равно висим. Может что-то здесь AREA IRQ0, CODE, READONLY?
aaarrr
Цитата(Zliva @ Aug 25 2009, 00:58) *
Все равно висим. Может что-то здесь AREA IRQ0, CODE, READONLY?

Ну, на зависании это и не должно было сказаться. Извините, если ввел в заблуждение.

Что-то не вижу в упор никаких проблем sad.gif Убрать только __irq из void irq_pioa_nin(void) - и все должно работать.

Цитата(Zliva @ Aug 25 2009, 00:58) *
Может что-то здесь AREA IRQ0, CODE, READONLY?

Нет, не может.
Zliva
Убрал строчку printf ("E1=%d\n",ENCODER1_Position); с тела прерывания. ЗАРАБОТАЛО
aaarrr
Я грешным делом думал, что printf у Вас под прерывания уже заточен. Тщательнее надо.
Zliva
Попробовал несколько вариантов обработки сигналов энкодера от PIOA. Целый день промаялся. Что-то ничего не получается. Вот код:
Код
void irq_pioa_nin(void){                
    unsigned int status = AT91C_BASE_SYS->PIOA_ISR;    
    
    if(status & ENCODER1_A)
        if ((pPIO->PIO_PDSR & ENCODER1_B) == 0) {
            ENCODER1_Position++;}
        else {
            ENCODER1_Position--;}                        
    if(status & ENCODER1_B)
        if ((pPIO->PIO_PDSR & ENCODER1_A) == 1) {
            ENCODER1_Position++;}
          else {
            ENCODER1_Position--;}                    
    AT91C_BASE_AIC->AIC_EOICR = status;
}

Хочу прутя в одну сторону получить возрастание значения ENCODER1_Position, в другую – убывания.
aaarrr
У Вас получается одинаковая обработка вне зависимости от полярности фронта, что неправильно.
Zliva
Цитата(aaarrr @ Aug 25 2009, 22:45) *
У Вас получается одинаковая обработка вне зависимости от полярности фронта, что неправильно.

Тогда как лучше сделать?
aaarrr
Цитата(Zliva @ Aug 25 2009, 23:53) *
Тогда как лучше сделать?

Я бы сделал примерно так:
CODE

signed char enc_step[16] =
{
// Previous Current Increment
// AB AB
//
0, // 00 00
1, // 00 01 +1
-1, // 00 10 -1
0, // 00 11
-1, // 01 00 -1
0, // 01 01
0, // 01 10
1, // 01 11 +1
1, // 10 00 +1
0, // 10 01
0, // 10 10
-1, // 10 11 -1
0, // 11 00
-1, // 11 01 -1
1, // 11 10 +1
0 // 11 11
};

void irq_pioa_nin(void)
{
unsigned int status = AT91C_BASE_SYS->PIOA_ISR, a, b, pa, pb;


a = (AT91C_BASE_PIOA->PIO_PDSR & ENCODER1_A) ? 1 : 0;
b = (AT91C_BASE_PIOA->PIO_PDSR & ENCODER1_B) ? 1 : 0;
pa = (status & ENCODER_A) ? a ^ 1 : a;
pb = (status & ENCODER_B) ? b ^ 1 : b;


ENCODER1_Position += enc_step[(pa << 3) | (pb << 2) | (a << 1) | b];


AT91C_BASE_AIC->AIC_EOICR = status;
}

Но еще не грех добавить аппаратный или программный антидребезг. В последнем случае прерывания непосредственно от выводов не нужны, все обрабатывается по таймеру.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.