My problem is the functioning of the PWM0 of the LM8330.
I am developing, for one of our products, a 5x10 keyboard driver, based on the lm8330 component using, to signal the events, the interrupt on the KPY11 column not used in the matrix.
In addition I need to use PWM0 on the other KPY10 column, also not used by the keyboard, for buzzer or back light regulation.
The keyboard works fine, while PWM0 just doesn't want to work.
I attach source code used to initialize lm8330 component. I want to clarify that I found any topic of my interest in the forum but it was not enough to make my problem understood.
Looking in the forum, I also found many inaccuracies on the way to write the word patterns of the pwm script. Sometimes the write order was reported as first LSB and then MSB, other times first MSB and then LSB.
I think it should be MSB followed by LSB in a continuous write. At least I hope.
In the attached source code there are 3 scripts, but none, as indicated in the comment, works as expected.
I am desperate, because I have run endless tests, in all combinations, without any positive results.
One thing only to report, on the keyboard. I had to repeat the command "CLKMODE" to set the "operating mode", otherwise the keyboard does not work, as if there was some instruction, in the keyboard programming, which puts it in sleep mode.
Thanks to those who can help me.
#define LM8330_CMD_SET_KBDSETTLE 0x01 /* Set KBDSETTLE time. Initial time for keys to settle, before the key-scan process is started*/ #define LM8330_CMD_SET_KBDBOUNCE 0x02 /* Set debouncing time. */ #define LM8330_CMD_SET_KBDSIZE 0x03 /* Set keypad size. Defines the physical keyboard matrix size*/ #define LM8330_CMD_SET_KBDDEDCFG 0x04 /* Set Dedicated Key Register. Defines if a key is used as a standard keyboard/GPIO pin or whether it is used as dedicated key input*/ #define LM8330_CMD_SET_KBDDEDCFG0 0x04 /* Set Dedicated Key Register. Defines if a key is used as a standard keyboard/GPIO pin or whether it is used as dedicated key input*/ #define LM8330_CMD_SET_KBDDEDCFG1 0x05 /* Set Dedicated Key Register. Defines if a key is used as a standard keyboard/GPIO pin or whether it is used as dedicated key input*/ #define LM8330_CMD_READ_KBDRIS 0x06 /* Get Keyboard Raw Interrupt Status register. Returns the status of stored keyboard interrupts*/ #define LM8330_CMD_READ_KINT 0x06 #define LM8330_CMD_READ_KBDMIS 0x07 /* Get Keypad Masked Interrupt Status Register. Returns the status on masked keyboard interrupts after masking with the KBDMSK register*/ #define LM8330_CMD_SET_KBDIC 0x08 /* Set Keypad Interrupt Clear Register. Setting these bits clears Keypad active Interrupts */ #define LM8330_CMD_SET_KBDMSK 0x09 /* Set Keypad Interrupt Mask Register. Configures masking of keyboard interrupts. Masked interrupts do not trigger an event on the Interrupt output */ #define LM8330_CMD_READ_KBDCODE0 0x0B /* Read the first detected key. */ #define LM8330_CMD_READ_KBDCODE1 0x0C /* Read the second detected key. */ #define LM8330_CMD_READ_KBDCODE2 0x0D /* Read the third detected key. */ #define LM8330_CMD_READ_KBDCODE3 0x0E /* Read the forth detected key. */ #define LM8330_CMD_READ_EVTCODE 0x10 /* KRead key Event from Code Register */ #define LM8330_CMD_SET_TIMCFG0 0x60 /* Set PWM Timer 0 Configuration Register. This register configures interrupt masking of the associated PWM channel*/ #define LM8330_CMD_SET_PWMCFG0 0x61 /* Set PWM Timer 0 Conf iguration Control Register. This register defines interrupt masking and the output behavior for the associated PWM channel */ #define LM8330_CMD_SET_PWMCFG1 0x69 /* Set PWM Timer 1 Conf iguration Control Register. This register defines interrupt masking and the output behavior for the associated PWM channel */ #define LM8330_CMD_SET_PWMCFG2 0x71 /* Set PWM Timer 2 Conf iguration Control Register. This register defines interrupt masking and the output behavior for the associated PWM channel */ #define LM8330_CMD_SET_TIMSWRES 0x78 /* Set PWM Timer Software Reset Registers. Reset control on all PWM timers */ #define LM8330_CMD_READ_TIMRIS 0x7A /* Read PWM Timer Interrupt Status Register. This register returns the raw interrupt status from the PWM timers 0,1 and 2.*/ #define LM8330_CMD_READ_TIMMIS 0x7B /* Read PWM Timer Masked Interrupt Status Register. This register returns the masked interrupt status from the PWM timers 0, 1 and 2. */ #define LM8330_CMD_SET_TIMIC 0x7C /* Set PWM Timer Interrupt Clear Register. This register clears timer and pattern interrupts. */ #define LM8330_CMD_SET_PWMWP 0x7D /* Set PWM Timer Pattern Pointer Register. Pointer to the pattern position inside the configuration register, which will be overwritten by the next write access to be PWMCFG register */ #define LM8330_CMD_SET_PWMCFG 0x7E /* PWM Script Register. Two-byte pattern storage register for a PWM script command indexed by PWMWP. PWMWP is automatically incremented*/ #define LM8330_CMD_SET_I2CSA 0x80 /* Set Slave Address Register. The address is internally applied after the next I2C STOP*/ #define LM8330_CMD_READ_MFGCODE 0x80 /* Read Manufacturer Code Register*/ #define LM8330_CMD_READ_SWREV 0x81 /* Read Software revision code of the LM8330 */ #define LM8330_CMD_SWRESET 0x81 /* Software Reset Register. The reset is only applied if the supplied parameter has the inverted value as SWBIT*/ #define LM8330_CMD_RSTCTRL 0x82 /* Software reset of specific parts of the LM8330 */ #define LM8330_CMD_RSTINTCLR 0x84 /* Clear NO Init/Power-On Interrupt Register . This register is used to clear the PORIRQ Interrupt. This interrupt is set every time the device returns from RESET (either POR, HW or SW Reset).*/ #define LM8330_CMD_CLKMODE 0x88 /* Clock Mode Register. This register controls the current operating mode of the LM8330 device. */ #define LM8330_CMD_CLKEN 0x8A /* Clock Enable Register. Controls the clock to different functional units. It is used to enable the functional blocks globally and independently */ #define LM8330_CMD_AUTOSLP 0x8B /* Auto-sleep Enable Register. This register controls the Auto-Sleep function of the LM8330 device */ #define LM8330_CMD_AUTOSLPTIL 0x8C /* Auto-Sleep Time Register Low byte. This register defines the activity time. If this time passes without any processing events then the device enters into sleep-mode, but only if AUTOSLP.ENABLE bit is set to 1. */ #define LM8330_CMD_AUTOSLPTIH 0x8D /* Auto-Sleep Time Register High byte*/ #define LM8330_CMD_READ_IRQST 0x91 /* Read Interrupt Global Interrupt Status Register. Returns the interrupt status from various on-chip function blocks */ #define LM8330_CMD_READ_INT 0x91 #define LM8330_CMD_SET_IOCFG 0xA7 /* Input/Output Pin Mapping Configuration Register. Configures usage of KPY[11:8] if not used for Keypad. */ #define LM8330_CMD_SET_IOPC0 0xAA /* Pull Resistor Configuration Register 0. Defines the pull resistor configuration for balls KPX[7:0]. */ #define LM8330_CMD_SET_IOPC1 0xAC /* Pull Resistor Configuration Register 1. Defines the pull resistor configuration for balls KPY[7:0].. */ #define LM8330_CMD_SET_IOPC2 0xAE /* Pull Resistor Configuration Register 2. Defines the pull resistor configuration for balls KPY[11:8].. */ /* Interrupt global status. */ #define INT_GPIOIRQ 0x01 /* GPIO interrupt */ #define INT_TIM0IRQ 0x02 /* Timer0 expiry */ #define INT_TIM1IRQ 0x04 /* Timer0 expiry */ #define INT_TIM2IRQ 0x08 /* Timer0 expiry */ #define INT_KBDIRQ 0x40 /* Keyboard interrupt (further key selection in keyboard module */ #define INT_PORIRQ 0x80 /* Supply failure on VCC. Also power-on is considered as an initial supply failure */ /* Keyboard Row Interrupt status. */ #define KINT_RSINT 0x01 /* Raw scan interrupt.Interrupt generated after keyboard scan, if the keyboard status has changed. */ #define KINT_RKLINT 0x02 /* Raw key lost interrupt indicates a lost key-code. */ #define KINT_REVTINT 0x04 /* Raw keyboard event interrupt.At least one key press or key release is in the keyboard event buffer */ #define KINT_RELINT 0x08 /* Raw event lost interrupt. More than 16 keyboard events have been detected and caused the event buffer to overflow */ /* Clock settings (CMD_CLKMODE). */ #define CLK_MODCTL 0x01 /* 00: SLEEP Mode, 01: Operation Mode .Writing to 00 forces the device to immediately enter sleep mode,*/ /* Clock settings (CMD_CLKEN). */ #define CLK_TIMEN 0x04 /* PWM Timer 0, 1, 2 clock enable */ #define CLK_KBDEN 0x01 /* Keyboard clock enable (enables/disables key scan) */ #define SCRIPT_1 //#define SCRIPT_2 //#define SCRIPT_3 static int lm8330_configure(struct lm8330_chip *lm) { int keysize = (lm->size_x << 4) | lm->size_y; int clock = (CLK_TIMEN | CLK_KBDEN); int debounce = lm->debounce_time >> 2; int active = lm->active_time >> 2; /* * Active time must be greater than the debounce time: if it's * a close-run thing, give ourselves a 12ms buffer. */ if (debounce >= active) active = debounce + 3; lm8330_write(lm, 2, LM8330_CMD_AUTOSLP, 0x00); /* disable autoslip */ lm8330_write(lm, 2, LM8330_CMD_CLKMODE, 0x01); /* set Operation mode */ lm8330_write(lm, 2, LM8330_CMD_CLKEN, clock); /* nable keyboard clock end timers */ lm8330_write(lm, 2, LM8330_CMD_SET_KBDSETTLE, 0x80); /* Set the keyscan settle time to 12 msec. */ lm8330_write(lm, 2, LM8330_CMD_SET_KBDBOUNCE, debounce); /* Set the keyscan debounce time */ lm8330_write(lm, 2, LM8330_CMD_SET_KBDSIZE, keysize); /* Set the keyscan matrix size to 5 rows x 10 columns */ lm8330_write(lm, 3, LM8330_CMD_SET_KBDDEDCFG, 0xFF, 0xFF); /* Confirm default value */ lm8330_write(lm, 2,LM8330_CMD_SET_IOCFG, 0x11); /* KPY10-> pwm, KPY11->IRQ */ lm8330_write(lm, 3,LM8330_CMD_SET_IOPC0, 0xAA, 0xAA); /* pull up resistor for row*/ lm8330_write(lm, 3,LM8330_CMD_SET_IOPC1, 0x55, 0x55); /* pulldown resistor for column 0-7*/ lm8330_write(lm, 3,LM8330_CMD_SET_IOPC2, 0x5A, 0x05); /* pulldown resistor for column 8-9*/ lm8330_write(lm, 2,LM8330_CMD_RSTINTCLR, 0x01); /* Clear Power On interrupt */ lm8330_write(lm, 2,LM8330_CMD_SET_KBDIC, 0x03); /* Clear all pending interrupts */ lm8330_write(lm, 2,LM8330_CMD_SET_KBDMSK, 0x0B); /* Configure interrupt masking */ /* PWM0 programming * */ lm8330_write(lm, 2, LM8330_CMD_SET_TIMCFG0, 0x10); /* Interrupt mask for PWM CYCIRQ0 */ lm8330_write(lm, 2, LM8330_CMD_SET_PWMCFG0, 0x08); /* CDIRQ disabled/masked, Pattern Generator disabled, PWM disabled,PWM off-state is low */ lm8330_write(lm, 2, LM8330_CMD_SET_TIMIC, 0x3F); /* This register clears timer and pattern interrupts */ lm8330_write(lm, 2, LM8330_CMD_SET_PWMWP, 0); /* set PWM SCRIPT pointer buffer */ #ifdef SCRIPT_1 // This script outputs a square wave with a duty cycle at 25%. Why??????????????????????????????? lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x40, 0x00); //0x40FF set duty cycle to 00% lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x01, 0x7F); //ramp 1 inc 126 lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x01, 0x7F); //ramp 1 inc 126 lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x01, 0xFF); //ramp 1 dec 126 lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x01, 0xFF); //ramp 1 dec 126 lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x00, 0x00); //goto start script #endif #ifdef SCRIPT_2 //This script outputs a square wave with a duty cycle that varies continuously from 0% to 25% (a minute or two) then outputs a square wave with a duty cycl 50%. Why?????????????????????????? lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x40, 0x7F); //set duty cycle to 50% lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0xBF, 0xC1); //loop lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x40, 0x00); //set duty cycle to 0% lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0xBF, 0xC1); //loop lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x40, 0xFF); //set duty cycle to 100% lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0xBF, 0xC1); //loop lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x00, 0x00); //go to start script #endif #ifdef SCRIPT_3 //This script outputs a square wave with a duty cycle that varies continuously from 0% to 25% (a minute or two), then stop. Why?????????????????????????? lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x40, 0x7F); //set duty cycle to 50% lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0xBF, 0xC1); //loop lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x40, 0x00); //set duty cycle to 0% lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0xBF, 0xC1); //loop lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x40, 0xFF); //set duty cycle to 100% lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0xBF, 0xC1); //loop lm8330_write(lm, 3, LM8330_CMD_SET_PWMCFG, 0x00, 0x00); //go to start #endif /* Command repeated because some keypad configuration instruction puts it in sleep mode. ?????????????? */ lm8330_write(lm, 2, LM8330_CMD_CLKMODE, 0x01); /*set Operation mode */ lm8330_write(lm, 2, LM8330_CMD_SET_PWMCFG0, 0x06); /* Start pwm script /* * Not much we can do about errors at this point, so just hope * for the best. */ return 0; }