реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Захват импульсов PS2 мыши через EXTI
pvo125
сообщение Feb 12 2016, 13:44
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 37
Регистрация: 9-04-14
Из: Черногорск Хакасия
Пользователь №: 81 299



Здравствуйте! Пытаюсь присоединить мышь 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 сэмплов в секунду.
Подскажите пожалуйста в каком направлении смотреть. Сами функции честно списал у другого автора. Вроде код рабочий да и не такие уж они сложные вроде все прозрачно. Тем более что при остановке считаются биты правильно.

Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Feb 12 2016, 17:23
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



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

На заре Кортексов от STM была тема повторного вхождения в прерывание в случае, когда команда сброса флага - последняя в обработчике. Там была тема с конвейером, слишком быстрым выходом из прерывания и т.п. Короче, вставьте __NOP() после сброса флага или еще лучше - __DSB();
Go to the top of the page
 
+Quote Post
hd44780
сообщение Feb 12 2016, 18:26
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 202
Регистрация: 26-08-05
Из: Донецк, ДНР
Пользователь №: 7 980



По-моему, NVIC_ClearPendingIRQ(EXTI9_5_IRQn); в прерывании лишнее.
Очистки бита в EXTI-PR вполне достаточно. и лучше загнать её внутрь ифа. Т.к. обработчик обрабатывает несколько прерываний.


--------------------
Чтобы возить такого пассажира, необходим лимузин другого класса.
(с) Мария Эдуарда
Go to the top of the page
 
+Quote Post
pvo125
сообщение Feb 13 2016, 04:40
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 37
Регистрация: 9-04-14
Из: Черногорск Хакасия
Пользователь №: 81 299



Цитата
Короче, вставьте __NOP() после сброса флага или еще лучше - __DSB();


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


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

Наверное придется цеплять 2 кнопки и вместо мыши щелкать такт данные и смотреть.
Может быть кто захватывал последовательности бит через внешние прерывания? Не обязательно мыши. Поделитесь опытом. Мне без кода просто на словах. Может быть у меня логика в целом не правильная.
Go to the top of the page
 
+Quote Post
Vasily Hohlov
сообщение Feb 14 2016, 18:10
Сообщение #5





Группа: Участник
Сообщений: 8
Регистрация: 26-09-08
Пользователь №: 40 508



предполагаю, что вы не отсылаете подтверждение по линии clock и мышка производит перепосылку данных. (моя ps/2 клавиатура шлет 16 раз) поэтому после брейка данные нормальные, а без него мусор.
Go to the top of the page
 
+Quote Post
pvo125
сообщение Feb 15 2016, 04:46
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 37
Регистрация: 9-04-14
Из: Черногорск Хакасия
Пользователь №: 81 299



Вот только что снял осциллограмму обмена между мышкой и ПК. И правда увидел что хост по линии clock после 11 импульса делает еще что то типа подтверждения переводя линию клок в низкий уровень тем самым как бы формируя 12 импульс. Дальше обе линии в 1 и пошел следующий байт. И так на каждом. Но вот про такое поведение я не читал. Странно что в нескольких местах описывают интерфейс PS2 и нигде не упоминают что нужно подтверждать мышке о приеме байта. Возможно были какие то изменения в интерфейсе а я смотрел везде старое описаниеюТак же нет такого в документе на саму микросхему (PAW3401) которая стоит в моих двух мышках с которыми экспериментировал. Это очень важное замечание. Переделаю программу попробую.
А вы не подскажите на сколько линию clock переводить в ноль. Сами параметры этого импульса подтверждения?
Go to the top of the page
 
+Quote Post
Vasily Hohlov
сообщение Feb 15 2016, 05:27
Сообщение #7





Группа: Участник
Сообщений: 8
Регистрация: 26-09-08
Пользователь №: 40 508



Цитата(pvo125 @ Feb 15 2016, 07:46) *
А вы не подскажите на сколько линию clock переводить в ноль. Сами параметры этого импульса подтверждения?

на сколько я помню - 30-50мкс. посмотрите журнал радио 4 за 2009 год.
еще проект https://github.com/gandro/stm32-ps2
Go to the top of the page
 
+Quote Post
pvo125
сообщение Feb 23 2016, 14:30
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 37
Регистрация: 9-04-14
Из: Черногорск Хакасия
Пользователь №: 81 299



В общем довел до ума мышку. Три недели все это продолжалось. Сам запутался на несколько рядов так что сложно сказать что было не так. В итоге сделал захват и подсчет импульсов с помощью таймера 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. Старался комменты расставлять. Если что не понятно спрашивайте! Отвечу!
Прикрепленные файлы
Прикрепленный файл  PS2_mouse.rar ( 3.94 килобайт ) Кол-во скачиваний: 10
 
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 6th July 2025 - 22:10
Рейтинг@Mail.ru


Страница сгенерированна за 0.01407 секунд с 7
ELECTRONIX ©2004-2016