Is it possible to read a data pin with PPI? (PS/2 bit banging using PPI)

Hi,

I am trying to implement a PS/2 bit banging driver. My initial attempt used the GPIO library and interrupts, but unfortunately the interrupts are not fast enough and oftentimes there are transmission errors due to missed bits.

Now I am exploring whether it would be possible to use PPI to read the data. 

PS2 uses a clock and data pin. The data pin is read on the falling edge of the clock pin. The frequency is approximately 10-16hz.

The PS2 data frame is 11bit:

  • Start bit
  • 8 data bits
  • Parity bit
  • Stop bit

I considered trying to use SPI, but it seems that it can‘t read odd number of bits. 

Now I’m exploring whether PPI would work. 

My idea is…

  1. Create a timer that counts whenever the clock pin triggers.

  2. Copy the data pin value to some kind of buffer every time the clock pin triggers
  3. When the timer reaches 11, copy the buffer using easy DMA to the cpu and trigger an interrupt to notify it. 
  4. Reset the timer counter so that it can start from scratch

Is something like this feasible?

If yes, could you please point me to some documentation on how to configure such PPI tasks? I couldn’t find any good explanations. 

I was able to find examples for counting, but not for storing the data pin value in a buffer array and for transmitting it using easy DMA.

Thank you so much,

Kim

Parents
  • Since the PS2 keyboard (internal) data transitions occur on the clock +ve edge and are subsequently sampled by an external device on the clock -ve edge the data line can be used as a single edge-per-bit signal to capture a counter/timer value via PPI as the data transition is known to be clean.

    One counter counts the Clock transitions from 0-10 (11 bits) and at the last bit captures a time giving the 11-bit clock period, which although varies between keyboards is very consistent over the 11-bits making up a single transmission for a given keyboard. Since the data is cleanly changed on the +ve edge of the clock only a single data transition occurs for each bit and this edge can be used to capture a timer value using the 5 x CC registers on (say) timer 4. There are a maximum of 5 negative transitions worst case, odd parity and 0xAA data value so 10 CC registers are required which means reusing registers and storing the captured values within the interrupt.

    Once each edge time has been captured for a complete single character, the 11-bit time can be used to accurately decode the actual character. Edit: Updated for both edge detection and time detection

    // 11-bit Data bit changes on clock +ve edge, sample value on clock -ve edge
    //
    // Standard character 0x21 - Single sample, single timer (T4), requires reload
    //
    // Idle 'Start'Bit 0'Bit 1'Bit 2'Bit 3'Bit 4'Bit 5'Bit 6'Bit 7'Par  'Stop | Idle
    //      |     |     |     |     |     |     |     |     |     |     |     | 11-Bit Framing
    //      |     |     |     |     |     |     |     |     |     |     |     |
    //         0     1     2     3     4     5     6     7     8     9     10   Counter 3
    //      |     |     |     |     |     |     |     |     |     |     |     |
    // --------+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--------
    //         |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | Clock
    //         |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
    //         +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+
    //      |     |     |     |     |     |     |     |     |     |     |     |
    // Idle 'Start'Bit 0'Bit 1'Bit 2'Bit 3'Bit 4'Bit 5'Bit 6'Bit 7'Par  'Stop | Idle
    // -----+     +-----+                       +-----+           +-----+-----+--------
    //      |     |     |                       |     |           |
    //      |     |     |                       |     |           |             Data Normal
    //      +-----+     +-----+-----+-----+-----+     +-----+-----+
    //
    //      +-----+     +-----+-----+-----+-----+     +-----+-----+
    //      |     |     |                       |     |           |             Data Invert
    //      |     |     |                       |     |           |
    // -----+     +-----+                       +-----+           +-----+-----+--------
    //      |     |     |     |     |     |     |     |     |     |     |     |
    //      |     |     |     |     |     |     |     |     |     |     |     | 11-Bit Framing
    // Idle 'Start'Bit 0'Bit 1'Bit 2'Bit 3'Bit 4'Bit 5'Bit 6'Bit 7'Par  'Stop | Idle
    //      |     |     |     |     |     |     |     |     |     |     |     |
    //      |     |     |                       |     |           |                                                Clear Reload
    //      |     |     |                       |     |           |       -- Edge 10   pTimer4->CC[4] = BT/2+(10*BT) *      3,0
    //      |     |     |                       |     |           |       -- Edge  9   pTimer4->CC[3] = BT/2+( 9*BT) -      2
    //      |     |     |                       |     |           |       -- Edge  8   pTimer4->CC[2] = BT/2+( 8*BT) -      1
    //      |     |     |                       |     |           |       -- Edge  7   pTimer4->CC[1] = BT/2+( 7*BT) -      0
    //      |     |     |                       |     |           |       -- Edge  6   pTimer4->CC[0] = BT/2+( 6*BT) -      -
    //      |     |     |                       |     |           +--------- Edge  5   pTimer4->CC[5] = BT/2+( 5*BT) *      -
    //      |     |     |                       |     +--------------------- Edge  4   pTimer4->CC[4] = BT/2+( 4*BT) -      -
    //      |     |     |                       +--------------------------- Edge  3   pTimer4->CC[3] = BT/2+( 3*BT) -      2
    //      |     |     +--------------------------------------------------- Edge  2   pTimer4->CC[2] = BT/2+( 2*BT) -      1
    //      |     +--------------------------------------------------------- Edge  1   pTimer4->CC[1] = BT/2+( 1*BT) -      0
    //      +--------------------------------------------------------------- Edge  0   pTimer4->CC[0] = BT/2         -      -
    //      |     |     |     |     |     |     |     |     |     |     |                                          Clear Reload
    //      |     |     |     |     |     |     |     |     |     |     +--- Stop bit  pTimer4->CC[4] = BT/2+(10*BT) *      3,0
    //      |     |     |     |     |     |     |     |     |     +--------- Parity    pTimer4->CC[3] = BT/2+( 9*BT) -      2
    //      |     |     |     |     |     |     |     |     +--------------- Bit 7     pTimer4->CC[2] = BT/2+( 8*BT) -      1
    //      |     |     |     |     |     |     |     +--------------------- Bit 6     pTimer4->CC[1] = BT/2+( 7*BT) -      0
    //      |     |     |     |     |     |     +--------------------------- Bit 5     pTimer4->CC[0] = BT/2+( 6*BT) -      -
    //      |     |     |     |     |     +--------------------------------- Bit 4     pTimer4->CC[5] = BT/2+( 5*BT) *      -
    //      |     |     |     |     +--------------------------------------- Bit 3     pTimer4->CC[4] = BT/2+( 4*BT) -      -
    //      |     |     |     +--------------------------------------------- Bit 2     pTimer4->CC[3] = BT/2+( 3*BT) -      2
    //      |     |     +--------------------------------------------------- Bit 1     pTimer4->CC[2] = BT/2+( 2*BT) -      1
    //      |     +--------------------------------------------------------- Bit 0     pTimer4->CC[1] = BT/2+( 1*BT) -      0
    //      +--------------------------------------------------------------- Start Bit pTimer4->CC[0] = BT/2         -      -

Reply
  • Since the PS2 keyboard (internal) data transitions occur on the clock +ve edge and are subsequently sampled by an external device on the clock -ve edge the data line can be used as a single edge-per-bit signal to capture a counter/timer value via PPI as the data transition is known to be clean.

    One counter counts the Clock transitions from 0-10 (11 bits) and at the last bit captures a time giving the 11-bit clock period, which although varies between keyboards is very consistent over the 11-bits making up a single transmission for a given keyboard. Since the data is cleanly changed on the +ve edge of the clock only a single data transition occurs for each bit and this edge can be used to capture a timer value using the 5 x CC registers on (say) timer 4. There are a maximum of 5 negative transitions worst case, odd parity and 0xAA data value so 10 CC registers are required which means reusing registers and storing the captured values within the interrupt.

    Once each edge time has been captured for a complete single character, the 11-bit time can be used to accurately decode the actual character. Edit: Updated for both edge detection and time detection

    // 11-bit Data bit changes on clock +ve edge, sample value on clock -ve edge
    //
    // Standard character 0x21 - Single sample, single timer (T4), requires reload
    //
    // Idle 'Start'Bit 0'Bit 1'Bit 2'Bit 3'Bit 4'Bit 5'Bit 6'Bit 7'Par  'Stop | Idle
    //      |     |     |     |     |     |     |     |     |     |     |     | 11-Bit Framing
    //      |     |     |     |     |     |     |     |     |     |     |     |
    //         0     1     2     3     4     5     6     7     8     9     10   Counter 3
    //      |     |     |     |     |     |     |     |     |     |     |     |
    // --------+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--------
    //         |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | Clock
    //         |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
    //         +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+
    //      |     |     |     |     |     |     |     |     |     |     |     |
    // Idle 'Start'Bit 0'Bit 1'Bit 2'Bit 3'Bit 4'Bit 5'Bit 6'Bit 7'Par  'Stop | Idle
    // -----+     +-----+                       +-----+           +-----+-----+--------
    //      |     |     |                       |     |           |
    //      |     |     |                       |     |           |             Data Normal
    //      +-----+     +-----+-----+-----+-----+     +-----+-----+
    //
    //      +-----+     +-----+-----+-----+-----+     +-----+-----+
    //      |     |     |                       |     |           |             Data Invert
    //      |     |     |                       |     |           |
    // -----+     +-----+                       +-----+           +-----+-----+--------
    //      |     |     |     |     |     |     |     |     |     |     |     |
    //      |     |     |     |     |     |     |     |     |     |     |     | 11-Bit Framing
    // Idle 'Start'Bit 0'Bit 1'Bit 2'Bit 3'Bit 4'Bit 5'Bit 6'Bit 7'Par  'Stop | Idle
    //      |     |     |     |     |     |     |     |     |     |     |     |
    //      |     |     |                       |     |           |                                                Clear Reload
    //      |     |     |                       |     |           |       -- Edge 10   pTimer4->CC[4] = BT/2+(10*BT) *      3,0
    //      |     |     |                       |     |           |       -- Edge  9   pTimer4->CC[3] = BT/2+( 9*BT) -      2
    //      |     |     |                       |     |           |       -- Edge  8   pTimer4->CC[2] = BT/2+( 8*BT) -      1
    //      |     |     |                       |     |           |       -- Edge  7   pTimer4->CC[1] = BT/2+( 7*BT) -      0
    //      |     |     |                       |     |           |       -- Edge  6   pTimer4->CC[0] = BT/2+( 6*BT) -      -
    //      |     |     |                       |     |           +--------- Edge  5   pTimer4->CC[5] = BT/2+( 5*BT) *      -
    //      |     |     |                       |     +--------------------- Edge  4   pTimer4->CC[4] = BT/2+( 4*BT) -      -
    //      |     |     |                       +--------------------------- Edge  3   pTimer4->CC[3] = BT/2+( 3*BT) -      2
    //      |     |     +--------------------------------------------------- Edge  2   pTimer4->CC[2] = BT/2+( 2*BT) -      1
    //      |     +--------------------------------------------------------- Edge  1   pTimer4->CC[1] = BT/2+( 1*BT) -      0
    //      +--------------------------------------------------------------- Edge  0   pTimer4->CC[0] = BT/2         -      -
    //      |     |     |     |     |     |     |     |     |     |     |                                          Clear Reload
    //      |     |     |     |     |     |     |     |     |     |     +--- Stop bit  pTimer4->CC[4] = BT/2+(10*BT) *      3,0
    //      |     |     |     |     |     |     |     |     |     +--------- Parity    pTimer4->CC[3] = BT/2+( 9*BT) -      2
    //      |     |     |     |     |     |     |     |     +--------------- Bit 7     pTimer4->CC[2] = BT/2+( 8*BT) -      1
    //      |     |     |     |     |     |     |     +--------------------- Bit 6     pTimer4->CC[1] = BT/2+( 7*BT) -      0
    //      |     |     |     |     |     |     +--------------------------- Bit 5     pTimer4->CC[0] = BT/2+( 6*BT) -      -
    //      |     |     |     |     |     +--------------------------------- Bit 4     pTimer4->CC[5] = BT/2+( 5*BT) *      -
    //      |     |     |     |     +--------------------------------------- Bit 3     pTimer4->CC[4] = BT/2+( 4*BT) -      -
    //      |     |     |     +--------------------------------------------- Bit 2     pTimer4->CC[3] = BT/2+( 3*BT) -      2
    //      |     |     +--------------------------------------------------- Bit 1     pTimer4->CC[2] = BT/2+( 2*BT) -      1
    //      |     +--------------------------------------------------------- Bit 0     pTimer4->CC[1] = BT/2+( 1*BT) -      0
    //      +--------------------------------------------------------------- Start Bit pTimer4->CC[0] = BT/2         -      -

Children
No Data
Related