Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Захват импульсов PS2 мыши через EXTI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
pvo125
Здравствуйте! Пытаюсь присоединить мышь PS2 к stm32f4. Отправку и принятие байт написал через ногодрыг. Далее Посылаю мышки серию команд (сброс - ответ, скорость сэмплов-ответ, включение в стрим режим). Далее мышь (правда через раз ) отвечает на все команды утвердительно ACK и переходит в стрим режим и начинает слать сэмпл по 3 байта (каждый из 11 бит) на каждое перемещение или нажатие кнопок. В общем все нормально сэмплы смотрел осциллом. Далее я просто пытаюсь через EXTI считать по 11 бит первый второй и третий байт и писать их в соответствующий буфер. Ниже функции которые делают это.
Код
void EXTI9_5_IRQHandler (void){
    if(EXTI->PR&EXTI_PR_PR6)
    {
        PS2_Mouse_ISR();
    }
    EXTI->PR=EXTI_PR_PR6;
    NVIC_ClearPendingIRQ(EXTI9_5_IRQn);
    }


Код
void PS2_Mouse_ISR(void){
    uint8_t temp;
    static uint8_t bit_pos=0;
    static uint8_t scancode=0;
    temp=HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7);
    if((bit_pos>=1)&&(bit_pos<=8))
    {
        scancode=scancode>>1;
        if(temp==GPIO_PIN_SET)
            scancode|=0x80;
    }
    bit_pos++;
    if(bit_pos>=11)
    {
        PS2_Mouse_CheckScancode(scancode);
        bit_pos=0;
        scancode=0;
    }
}


Код
void PS2_Mouse_CheckScancode(uint8_t scan){
    static uint8_t count_byte=0;
    if(PS2_MOUSE.status==MOUSE_AKTIV)
    {
        PS2_MOUSE_VAR.buff[count_byte]=scan;
        count_byte++;
        if(count_byte>=3)
        {
            count_byte=0;
            PS2_MOUSE.status=MOUSE_NEW_DATA;
        }
    
    }
}



Если брейкпойнт ставлю на строчку PS2_Mouse_CheckScancode(scancode); те после прияния первых 11 бит (это статусный байт он содержит инфу о нажатии о направлении движения) то при дерганье мыши получаю правильный код scancode=0х08 или scancode=0х0А scancode=0х09 . Т е когда делается пауза после принятия первого байта он оказывается верным. Если же без брейкпоинта то принимаю совершенно непонятные цифры. Такое ощущение как если сбивается счетчик bit_pos.
Пробовал объявлять переменные count_byte bit_pos scancode как volatile. Но нет измениния.

Получается если я ставлю брейк после принятия первого байта в сэмпле или даже всех 3 байт они правильные. (по крайней мере первый статусный там перемещение по х и у нужно в динамике смотреть). А как только начинается сплошной поток сэмплов то приходит можно сказать мусор.

Может быть при паузе флаги успевают сбрасываться (в NVIC и EXTI->PR) а при потоке нет и получаю повторные вхождения? Но с
другой стороны скорость мыши не большая. Частота самих импульсов около 12 кГц а частота следования самих сэмплов вообще настраивал 20 сэмплов в секунду.
Подскажите пожалуйста в каком направлении смотреть. Сами функции честно списал у другого автора. Вроде код рабочий да и не такие уж они сложные вроде все прозрачно. Тем более что при остановке считаются биты правильно.

KnightIgor
Цитата(pvo125 @ Feb 12 2016, 14:44) *

На заре Кортексов от STM была тема повторного вхождения в прерывание в случае, когда команда сброса флага - последняя в обработчике. Там была тема с конвейером, слишком быстрым выходом из прерывания и т.п. Короче, вставьте __NOP() после сброса флага или еще лучше - __DSB();
hd44780
По-моему, NVIC_ClearPendingIRQ(EXTI9_5_IRQn); в прерывании лишнее.
Очистки бита в EXTI-PR вполне достаточно. и лучше загнать её внутрь ифа. Т.к. обработчик обрабатывает несколько прерываний.
pvo125
Цитата
Короче, вставьте __NOP() после сброса флага или еще лучше - __DSB();


Да я так делал. Пробовал __DSB(); и даже __ISB(); Но нет разницы. Правильно захватывает биты только при брейке в прерывании как выше описывал.
Цитата
По-моему, NVIC_ClearPendingIRQ(EXTI9_5_IRQn); в прерывании лишнее.


Да по моему тоже pending bit в самом NVIC не должен устанавливаться пока в прерывании. Там частота не большая 12 кГц должен успевать выскакивать до следующего среза.Но это я уж так как говориться когда мысли кончились начал методом тыка. Типа может поможет. biggrin.gif

Наверное придется цеплять 2 кнопки и вместо мыши щелкать такт данные и смотреть.
Может быть кто захватывал последовательности бит через внешние прерывания? Не обязательно мыши. Поделитесь опытом. Мне без кода просто на словах. Может быть у меня логика в целом не правильная.
Vasily Hohlov
предполагаю, что вы не отсылаете подтверждение по линии clock и мышка производит перепосылку данных. (моя ps/2 клавиатура шлет 16 раз) поэтому после брейка данные нормальные, а без него мусор.
pvo125
Вот только что снял осциллограмму обмена между мышкой и ПК. И правда увидел что хост по линии clock после 11 импульса делает еще что то типа подтверждения переводя линию клок в низкий уровень тем самым как бы формируя 12 импульс. Дальше обе линии в 1 и пошел следующий байт. И так на каждом. Но вот про такое поведение я не читал. Странно что в нескольких местах описывают интерфейс PS2 и нигде не упоминают что нужно подтверждать мышке о приеме байта. Возможно были какие то изменения в интерфейсе а я смотрел везде старое описаниеюТак же нет такого в документе на саму микросхему (PAW3401) которая стоит в моих двух мышках с которыми экспериментировал. Это очень важное замечание. Переделаю программу попробую.
А вы не подскажите на сколько линию clock переводить в ноль. Сами параметры этого импульса подтверждения?
Vasily Hohlov
Цитата(pvo125 @ Feb 15 2016, 07:46) *
А вы не подскажите на сколько линию clock переводить в ноль. Сами параметры этого импульса подтверждения?

на сколько я помню - 30-50мкс. посмотрите журнал радио 4 за 2009 год.
еще проект https://github.com/gandro/stm32-ps2
pvo125
В общем довел до ума мышку. Три недели все это продолжалось. Сам запутался на несколько рядов так что сложно сказать что было не так. В итоге сделал захват и подсчет импульсов с помощью таймера TIM4 на ножке PB6 (clock ps/2). Так как у меня почему то постоянно сбивалась переменная которая отвечает за подсчет входных фронтов на выводе clock (или битов проще). Пробовал делать ее volatile но не было результата. Ногу data выбрал PB7 так было удобно но в принципе data может быть на любом свободном выводе.
Несколько замечаний по поводу того что обсуждалось выше.
-Мышь работает при 3 вольтовом питании ([хотя для контроллера в мыши PAW3401 написано 4.5-5.5 вольт)
-Мыши не нужно посылать подтверждение от хоста как я писал выше( было на осциллограмме от ПК.)
-В файле PS2_Mouse.c есть функция PS2_Mouse_GetData() ее я честно скопировал у автора и не переделывал почти.Она нормально преобразует данные из входных буферов в перемещение по х и по у и нажатие кнопок. Одно не мог понять в данной функции почему нет обработки флагов переполнения для х и у. Но в итоге я себе не так представлял работу мыши. Мышь отправляет величину перемещения не абсолютные значения а только изменение по х и у между посылками сэмплов. Потому что после каждой посылки счетчики перемещения сбрасываются в 0. В общем флаги переполнения просто не учитываются. При стандартных настройках 100 сэмплов с секунду и при разрешении в 4 мм на отсчет чтобы произошло переполнение нужно катнуть мыщь на 256/4=64 мм за 10 милисекунд. Или 6 метров в секунду. Думаю для рабочего стола где обитает мышь при стандартных настройках можно не учитывать переполнение. Хотя можно и на такое наверное извратиться. Может я и не прав но все работает и без этого.
-В функции PS2_Mouse_Tx(uint8_t cmd) после задержки для линии clock нужно обнулять таймер. TIM->CNT=0. По ходу это какой то 'костыль' но без этого не работает. Сам теоретически не могу сказать почему. Только экспериментальным путем вычислил. Иначе при старте первый байт отправляется правильно а вот следующие нет. Так как таймер после посылки остается в значении 1 и для последующей его нужно обнулять.

Прикрепляю файлы. Сам использовал мышь с теми настройками которые сохранены в PS2_Mouse_Start() и не закомментированы. Работа с мышью в таком порядке Сначала PS2_Mouse_Init(); затем PS2_Mouse_Start(); После этого в прерывании от таймера 100 раз в секунду запускаю функцию PS2_Mouse_GetData(); для обновления координат указателя мыши.
Прерывание от таймера который захватывает такты мыши. Мышь отправляет сэмплы 60 раз в секунду. Приемлемо для экрана 480 на 272.
Код
void TIM4_IRQHandler(void){
    
    //if(PS2_MOUSE.status==MOUSE_AKTIV)
    if(TIM4->SR&TIM_SR_UIF)
        {
            TIM4->SR&=~TIM_SR_TIF;
            if(PS2_MOUSE_VAR.mode==RX_MODE)
                PS2_Mouse_CheckScancode(scancode);
            else if (PS2_MOUSE_VAR.mode==TX_MODE)
                PS2_MOUSE_VAR.mode=RX_MODE;
            
            TIM4->SR&=~TIM_SR_UIF;
        }
    else if(TIM4->SR&TIM_SR_TIF)
        {
            PS2_Mouse_ISR();
            TIM4->SR&=~TIM_SR_TIF;
        }
}

Прерывание от таймера который вызывает GetData и заносит данные в GUI 100 раз в секунду.
Код
void TIM6_DAC_IRQHandler(void)
{
  /* USER CODE BEGIN TIM6_DAC_IRQn 0 */
        uint32_t temp;
    if(Input_Device==INPUT_DEV_MOUSE)
    {
        if(PS2_MOUSE.status==MOUSE_NEW_DATA)
        {    
            PS2_Mouse_GetData();
            PS2_MOUSE.status=MOUSE_AKTIV;
            State.x=PS2_MOUSE.xPos;
            State.y=272-PS2_MOUSE.yPos;
            State.Pressed=PS2_MOUSE.LButton;
        }
        else
        {    
            GUI_MOUSE_GetState(&State);
            if(State.Pressed==1)
            {
                State.Pressed=0;
                GUI_MOUSE_StoreState(&State);//GUI_TOUCH_StoreStateEx(&State);    
            }
        }    
    }
        TIM6->SR&=~TIM_SR_UIF;                             //Сбрасываем флаг UIF
}


Драйвер написан на CMSIS. Сам проекту меня на HAL но долго не мог запустить и в итоге упрощал все где можно чтоб заработало получилось CMSIS. Старался комменты расставлять. Если что не понятно спрашивайте! Отвечу!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.