This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LM8330 I2C Keypad Controller. Need some assistance with keypad scanning and PWM scripts

I am scanning a keypad of 8 rows x 6 columns (48 keys)

Some questions:

When a column is active (scanned), is the signal low or high? Is this logic selectable? Is it driven as push-pull or open-drain?

What is the preferred arrangement of pullup, pulldown, or no-pull resistors on rows and columns? (The example shows pull downs on Y, Pull ups on X)

An example configuration and script for the PWM would be great. Using them to drive some LED indicators and a piezo element (for sound - chirps)

Can the PWM generate a 1 kHz square wave?

I can read and write to registers at this point. Any hints on configuring and general use of this device would be greatly appreciated.

Thanks,

  • Hello Guillot,

    I have reached out to the appropriate apps engineer to respond to this question.
  • Jonathan,

    Thank you and I look forward to hearing from the Application Engineer.

    Doug

  • Hi Doug

    When the column is scanned the KPY pin is driven low and is not selectable. The KPY is configured as open-drain.
    The KPX pins are configured as Input with pull-up and KPY pins are configured as hi-z output with pull-down.
    Yes, the pwm can be used to generate a 1 kHz square wave.

    Best regards,
    Randy
  • Hi Randy,

    If KPY pins are open-drain, why are they also configured with pull-downs? There could be no change in the logic state. Am I missing something?

    Do you have an example script to drive a PWM at 1 kHz? Or any example script of any PWM action? Just need to get started.

    Thanks,

    Doug

    P.S. Since I now know that KPY pins are open drain, if I set the pins to have pull ups and start the scanning, I should be able to see the scan pulses with an oscilloscope, right?

  • Hi Doug

    The KPY pull-down ensures that the pin is low.  When a key is pressed the KPX pull-up is connected to the KPY pull-down which wakes up the scanning process (KPY input pulled-up).  After the device wakes up it starts driving KPY pin low one at a time to detect which KPX pin is connected.  You can see the scan activity by pressing a key connected between any KPX and KPY combination and observe on a scope.

    I will send out a pwm example tomorrow.

    Randy

  • Hi Randy,
    Thanks for helping me understand the scan mechanism.
    In my test, I set up a 3 column x 4 row matrix.
    IOPC0 = 0x00aa (pull ups on KPX[3:0])
    IOPC1 = 0x0015 (pull downs on KPY[2:0])
    KBDSIZE = 0x43
    KBDDEDCFG=0x0c01

    In idle condition (no keys pressed), all of the KPY pins are low, and all of the KPX pins are high.

    When I press a key I see that the corresponding KPY pin does not get pulled HIGH as expected, but that the corresponding KPX pin gets pulled LOW! In other words the KPY pulldown appears to be the "stronger" of the two pins.

    Obviously I have configured something wrong.

    Thanks,
    Doug
  • Hi Doug

    There are two examples below.  PWM 1 sets fixed duty cycle pwm that remains on.  PWM2 will ramp up then down and then turn off.

    The PWM frequency is fixed at 125 Hz (32 kHz OSC/255).

    // Enable PWM clock and Keyscan clock
    0x8a, 0x05

    // *****   Configure PWM 1   *****

    // PWM1 Fixed 25% duty cycle
    0x7d, 0x20  // PWM1 Pointer
    0x7e, 0x40, 0x40 // Set PWM1 to 25% Duty Cycle
    0x7e, 0x01, 0x02 // Ramp increment 1, step 2
    0x7e, 0x02, 0xa0   // Loop to Addr 02 (fixed duty cycle, ramp not repeated)

     delay(40);
    // *****   Configure PWM 2   *****
    // PWM2 ramp up then back down and halt

    0x7d, 0x40  // PWM2 Pointer
    0x7e, 0x80, 0x40   // Set PWM2 to 50% Duty Cycle
    0x7e, 0x01, 0x08 // Ramp increment 1, step 8
    0x7e, 0x81, 0xbf   // Repeat Loop to Addr 01 63 times
    0x7e, 0x01, 0x08 // Ramp increment 1, step 8
    0x7e, 0x83, 0xbf   // Repeat Loop to Addr 03 63 times
    0x7e, 0x01, 0x08 // Ramp increment 1, step 8
    0x7e, 0x85, 0xbf   // Repeat Loop to Addr 05 63 times
    0x7e, 0x01, 0x08 // Ramp increment 1, step 8
    0x7e, 0x87, 0xbf   // Repeat Loop to Addr 07 63 times
    0x7e, 0x81, 0x08 // Ramp decrement 1, step 8
    0x7e, 0x89, 0xbf   // Repeat Loop to Addr 09 63 times
    0x7e, 0x81, 0x08 // Ramp decrement 1, step 8
    0x7e, 0x8b, 0xbf   // Repeat Loop to Addr 11 63 times
    0x7e, 0x81, 0x08 // Ramp decrement 1, step 8
    0x7e, 0x8d, 0xbf   // Repeat Loop to Addr 13 63 times
    0x7e, 0x81, 0x08 // Ramp decrement 1, step 8
    0x7e, 0x8f, 0xbf   // Repeat Loop to Addr 15 63 times
    0x7e, 0x00, 0xd8   // Halt PWM

    0x69, 0x0f    // Start PWM1 Command
    0x71, 0x0f    // Start PWM2 Command

    Let me know if you have any other questions.

    Best regards,

    Randy

  • Hi Doug

    I don't see anything incorrect in your initialization, are you following the sequence on page 12 of the datasheet?

    Randy
  • Randy,
    I am following that example.
    I added in a call to clear the PORIRQ Interrupt (in the IRQST register)
    So on any switch closure, the corresponding KPY pin should be pulled HIGH, right?
    I am still seeing the KPY pin stay low during a closure, with the corresponding KPX pin going LOW.
    Doug

    Here is an extract of my code:
    //1 byte: RSTINTCLR 0x84
    test_data_tx[0] = 0x01;
    keypad_write(KBD_RSTINTCLR, 1);
    //5 bytes:
    test_data_tx[0] = 0x80; //KBDSETTLE (0x01). Set settle time to 12 msec
    test_data_tx[1] = 0x80; //KBDBOUNCE (0x02). Set debounce time to 12 msec
    test_data_tx[2] = 0x34; //KBDSIZE (0x03). 7:4 # of rows (2-8), 3:0 # of columns (2-12)
    test_data_tx[3] = 0x04; //KBDDEDCFG (0x04). X[7:2], Y[11:10]. USE 3 Rows: X2:0
    test_data_tx[4] = 0x03; //KBDDEDCFG (0x05). Y[9:2]. USE 4 Cols: Y3:0
    keypad_write(KBD_KBDSETTLE, 5);
    //1 byte:
    test_data_tx[0] = 0x17; //IOCFG (0xA7). Enable PWM0,1,2. Enable KPY11 as IRQN output.
    keypad_write(KBD_IOCFG, 1);
    //4 bytes:
    test_data_tx[0] = 0x00; //IOPC0 (0xAA). '10' = Pullup resistors for KPX[7:4]. UNUSED
    test_data_tx[1] = 0x2a; //IOPC0 (0xAB). Pullup resistors for KPX[3:0]. USE 3 Rows: X2:0
    test_data_tx[2] = 0x00; //IOPC1 (0xAC). No Pull resistors for KPY[7:4]. UNUSED
    test_data_tx[3] = 0x55; //IOPC1 (0xAD). '01' = Pulldown resistors for KPY[3:0]. USE 4 Cols: Y3:0
    keypad_write(KBD_IOPC0, 4);
    //2 bytes:
    test_data_tx[0] = 0x03; //KBDIC (0x08). Clear any pending interrupts
    test_data_tx[1] = 0x03; //KBDMSK (0x09). Enable keyboard interrupts
    keypad_write(KBD_KBDIC, 2);
    //1 byte: CLKEN 0x8A
    test_data_tx[0] = 0x01; //CLKEN (0x8A). Enable keyscan clock. set bit 0
    keypad_write(KBD_CLKEN, 1);
  • Hi Doug

    Thank you for sending your entire init sequence.
    The command to 0x88, 0x01 needs to be added. (CLKMODE = Operation Mode)

    Randy
  • Hi Randy,
    With that last change to set CLKMODE to 1, I was able to get the keypad scan working!

    It's almost perfect. Except I'm getting 2 event codes for each switch in the KPX0 row (the first event code is correct, second event codes are from row "4", examples 0x40, 0x41, etc.), all other rows give the correct single event code.

    Just a quick note that after setting CLKMODE, there seems to be a need to wait at least several milliseconds before clearing pending interrupts (by writing 0x03 to KBDIC). Can you comment on this?

    Looking at the PWM scripting, I noticed you placed a delay before writing a script for PWM2. Why is this?

    I will now try the PWM outputs.

    Thanks so much! You've been extremely helpful.
    Doug
  • Hi Randy,
    So far I have not been able to get any output from the PWM. I am currently trying to implement the first example you presented (PWM1 to 25%)
    I have trouble interpreting IOCFG bit assignments for BALLCFG. Table 49 is confusing. I eventually want to use PWM0, 1, and 2 simultaneously. But for now just getting an output on PWM1 is fine.
    Please review this code snippet:
    Thanks in advance,
    Doug

    //RED LED on KPY9 (PWM1)
    //Fixed 25% duty cycle
    //PWMCFG1
    test_data_tx[0] = 0x06;//Pattern Gen Enabled, PWM enabled, LOW when PWM is OFF
    keypad_write(KBD_PWMCFG1, 1);
    //GPIOPDIR2
    test_data_tx[0] = 0x0f; //KPY[11:8] all output
    keypad_write(KBD_GPIOPDIR2, 1);

    //PWM1 Pointer
    test_data_tx[0] = 0x20;
    keypad_write(KBD_PWMWP, 1);
    //Set PWM1 to 25% Duty Cycle
    test_data_tx[0] = 0x40;
    test_data_tx[1] = 0x40;
    keypad_write(KBD_PWMCFG, 2);
    //Ramp increment 1, step 2
    test_data_tx[0] = 0x01;
    test_data_tx[1] = 0x02;
    keypad_write(KBD_PWMCFG, 2);
    //Loop to Addr 02 (fixed duty cycle, ramp not repeated)
    test_data_tx[0] = 0x02;
    test_data_tx[1] = 0xa0;
    keypad_write(KBD_PWMCFG, 2);

    //IOCFG: CAUTION! is this correct?!
    test_data_tx[0] = 0x02; //configure KPY[10:8} as PWM0,1,2.
    keypad_write(KBD_IOCFG, 1);
    //CLKEN
    test_data_tx[0] = 0x04; //Enable PWM
    keypad_write(KBD_CLKEN, 1);
    //TIMIC
    test_data_tx[0] = 0x3f; //TIMIC: Clear any pending interrupts
    keypad_write(KBD_TIMIC, 1);
  • Hi Doug

    It looks like you are getting a SF key press detected, change KBDIC for 03 to 83 (disable SF keys).

    When enabled the key scan sequence is executed which takes a few milliseconds.

    This was a typo, no need for the delay.

    Randy

  • Hi Randy,
    I tried that but the problem still persists. I added an event queue and now I am able to see both the key down and key release events (no breakpoints to stop the debugging)
    I tried a test defining a 2 row x 4 col matrix and the problem went away - there were no extra key events.
    To recap the problem:
    Defined a 3 row x 4 column matrix.
    All keys in rows "1" and "2" return proper key down and key up event code pairs
    All keys in row "0" return the proper event pair, plus an extra pair. For the "0" row, "0" column key the received sequence is
    0x00, 0x40, 0x80, 0xc0 (0x00 and 0x80 being the expected event codes)

    Please note that I have outstanding questions on the PWM operation (see Nov 11, 2015 7:42 AM )

    Thanks,
    Doug
  • Hi Doug

     

    I have pasted in your sequence below with corrections highlighted.

    This sequence will enable the key scan and pwm and should clear up the dedicated key press you were getting on row 0.

     

    Here is an extract of my code:

    //1 byte: RSTINTCLR 0x84

    test_data_tx[0] = 0x01;

    keypad_write(KBD_RSTINTCLR, 1);

    //5 bytes:

    test_data_tx[0] = 0x80; //KBDSETTLE (0x01). Set settle time to 12 msec

    test_data_tx[1] = 0x80; //KBDBOUNCE (0x02). Set debounce time to 12 msec

    test_data_tx[2] = 0x34; //KBDSIZE (0x03). 7:4 # of rows (2-8), 3:0 # of columns (2-12)

    test_data_tx[3] = 0xFF; //KBDDEDCFG (0x04). X[7:2], Y[11:10]. USE 3 Rows: X2:0

    test_data_tx[4] = 0xFF; //KBDDEDCFG (0x05). Y[9:2]. USE 4 Cols: Y3:0

    keypad_write(KBD_KBDSETTLE, 5);

    //1 byte:

    test_data_tx[0] = 0x11; //IOCFG (0xA7). Enable PWM0,1,2. Enable KPY11 as IRQN output.

    keypad_write(KBD_IOCFG, 1);

    //4 bytes:

    test_data_tx[0] = 0x00; //IOPC0 (0xAA). '10' = Pullup resistors for KPX[7:4]. UNUSED

    test_data_tx[1] = 0x2a; //IOPC0 (0xAB). Pullup resistors for KPX[3:0]. USE 3 Rows: X2:0

    test_data_tx[2] = 0x00; //IOPC1 (0xAC). No Pull resistors for KPY[7:4]. UNUSED

    test_data_tx[3] = 0x55; //IOPC1 (0xAD). '01' = Pulldown resistors for KPY[3:0]. USE 4 Cols: Y3:0

    keypad_write(KBD_IOPC0, 4);

    //2 bytes:

    test_data_tx[0] = 0x03; //KBDIC (0x08). Clear any pending interrupts

    test_data_tx[1] = 0x03; //KBDMSK (0x09). Enable keyboard interrupts

    keypad_write(KBD_KBDIC, 2);

    //1 byte: CLKEN 0x8A

    test_data_tx[0] = 0x01; //CLKEN (0x8A). Enable keyscan clock. set bit 0

    keypad_write(KBD_CLKEN, 1);

     

    //RED LED on KPY9 (PWM1)

     //Fixed 25% duty cycle

     //PWMCFG1

    test_data_tx[0] = 0x06;//Pattern Gen Enabled, PWM enabled, LOW when PWM is OFF

     keypad_write(KBD_PWMCFG1, 1); --- MOVE to last command after clearing interrupts

    //GPIOPDIR2

     test_data_tx[0] = 0x0f; //KPY[11:8] all output

     keypad_write(KBD_GPIOPDIR2, 1);                       NOT NEEDED

     

     //PWM1 Pointer

     test_data_tx[0] = 0x20;

     keypad_write(KBD_PWMWP, 1);

     //Set PWM1 to 25% Duty Cycle

     test_data_tx[0] = 0x40;

     test_data_tx[1] = 0x40;

     keypad_write(KBD_PWMCFG, 2);

     //Ramp increment 1, step 2

     test_data_tx[0] = 0x01;

     test_data_tx[1] = 0x02;

     keypad_write(KBD_PWMCFG, 2);

     //Loop to Addr 02 (fixed duty cycle, ramp not repeated)

     test_data_tx[0] = 0x02;

     test_data_tx[1] = 0xa0;

     keypad_write(KBD_PWMCFG, 2);

     

     //IOCFG: CAUTION! is this correct?!

     test_data_tx[0] = 0x02; //configure KPY[10:8} as PWM0,1,2.

     keypad_write(KBD_IOCFG, 1);    NOT NEEDED

     //CLKEN

     test_data_tx[0] = 0x04; //Enable PWM

     keypad_write(KBD_CLKEN, 1);

     //TIMIC

     test_data_tx[0] = 0x3f; //TIMIC: Clear any pending interrupts

     keypad_write(KBD_TIMIC, 1);

     

    Let me know if you need anything else.

     

    Randy

  • Randy,
    Thanks, I will try that and post a response.
    The other issue regarding multiple sets of event codes has been resolved -There appears to be short circuit between KPX0 and KPX5 on our HW.
    Thanks,
    Doug
  • Hi Randy,

    I am adding support for special function keys to this product and need some assistance. First KPY0-KPY5 are used for column scanning. This is working fine. KPY6 and KPY7 are to be used for SF keys (one on each KPY line).

    What is the circuit for a SF key? Is it a switch that when closed pulls up through a resistor to Vdd? What would be an appropriate value for this resistor?

    In this case I am setting

    KBDDEDCFG to 0xFFCF

    (Note that KBDSIZE is 0x86)

    Presently I can't get an interrupt when pulling KPY6 (or KPY7) high through a 10k resistor.

    Are there other registers that need to be configured to support this functionality?

    Is the SF scan part of the Matrix scan process? Can the SF scan be seen on an oscilloscope?

    Thanks,

  • I would like to add that for the SF keys, it is most ideal to have a switch pull each KPY line to ground. We have an intelligent reset controller monitoring these two lines and they are active low.
    For my "active high" test I did configure IOPC1 so that the KPY lines have pull downs.
  • Hi Doug

    The SF key connects GND to the KPX input (refer to figure 3 on page 9). Also make sure that bit 7 of Register 0x08 is set low (refer to Table 30 on page 21).

    Randy
  • Hi Randy,
    We're locked in to our HW design and our "dedicated keys" are connected to KPY7 and KPY6. When the switches are closed, the inputs are grounded. There are external resistor pull ups on these lines.

    So I have been trying without success to setup the GPIO on these pins to INTERRUPT on RISING and FALLING EDGES. The problem I am seeing is that I am unable to clear the IRQ line upon detection of the FALLING edge (the behavior is as if it is "level" sensitive). It seems that it can't be cleared until the user releases the button. I've used code in a loop to sample the IRQST register and keep trying to reset the bit in GPIOIC1 register. I've also monitored GPIORIS1 and GPIOPDATA1. GPIORIS1 shows that the interrupt condition is still present, even after clearing the bit in the GPIOIC1 register. The logic hits a breakpoint (interrupt is finally cleared) at the moment the switch is released.

    So basically the most important thing is that even though the button might still be pressed, that the driver can clear the interrupt condition and hence clear the IRQ line.

    The setup is
    write 0xC0 to GPIOIBE1 (either edge)
    write 0xC0 to GPIOIE1 (turn on the interrupts)

    other pertinent registers are
    KBDSIZE = 0x86
    KBDDEDCFG = 0xFFFF
    KBDIOCFG = 0x11 (PWM2/1/0 in use)
    SROFF bit in KBDIC is set (SF keys not scanned)
    CLKEN = 0x05

    all other GPIO registers are in the default setting

    Thanks for your assistance,
    Doug
  • Hi Doug

    Can you confirm that GPIOIS1 at addr 0xCA bits 7:6 are set low?
    This register might need to be written after setting CLKEN.
    If they are I'll need to dig into this a little more next week as it looks like all other register settings are correct.

    Best regards,
    Randy
  • Hi Randy,
    I just explicitly wrote 0 to GPIOIS1 (0xCA) and then verified the write. I did this after setting CLKEN to 0x05 and re-tested. My test loop still executes until I release the switch, which tells me it's acting like a level-sensitive interrupt.
    Best Regards,
    Doug
  • Hi Doug

    Are you clearing the GPIO interrupt by writing to register 0xDD?
    Also make sure that bits 5:4 in register 0x03 are set high.
    Otherwise I don't see any issue when running this here.

    Best regards,
    Randy