Hello!
I want to use a QT411 touch-slider chip with SPI. Is supports only 40kHz SPI and I think it’s not a good idea to use the prepared software SPI for J19 on the STM32-Core (just ways too fast). So I need to write my own software SPI. However, one problem occurs: Between the clock pulses, there is a long period of time to wait to get 40kHz SPI. I could use the MIOS32-delay functions, but I don’t want to slow down my application by waiting long times. So here we come to multitasking: Does MIOS32 perform any kind of multitasking? Does “waiting” slow down my application and “eat” cycles, or does it simply do other things while waiting?
No matter, what the answer is, the safest way would be setting up a timer @30us and doing each step of the data transfer within this timer routine. This is what I did toevaluate my design, but it dosn’t work so far. I set up a timer routine and a global variable containing a number for the next step to be done.
This is the init function:
// Inits the QT411 chip and a timer for slow spi
// returns < 0 on error
//////////////////////////////////////////////////////////////////
s32 KEYTAR_QT411_Init(u32 mode)
{
if( mode != 0 )
return -1; // only mode 0 supported
// Pin 0 on J19 for data-ready input (= the device is ready to for communication)
MIOS32_BOARD_J5_PinInit(0, MIOS32_BOARD_PIN_MODE_INPUT);
// IO configuration
MIOS32_SPI_IO_Init(2, MIOS32_SPI_PIN_DRIVER_STRONG_OD);
// Set up a timer with 30us period
MIOS32_TIMER_Init(1, 30, KEYTAR_QT411_Timer, MIOS32_IRQ_PRIO_MID);
// set slave-select line to high (idle)
MIOS32_SPI_RC_PinSet(2, 1, 1);
return 0;
}
Data is sent this way:
// pushes a byte into Outbuffer and starts transmission
// returns < 0 on error (buffer full: -1)
//////////////////////////////////////////////////////////////////
s32 KEYTAR_QT411_Send(u8 data)
{
// Transfer in progress?
if (QT411State != 0) return -1;
QT411OutBuffer = data;
// Set state to "waiting" => we wait for the chip to wake up from sleep
QT411State = -1;
return 0;
}
And this is the timer and the variables:
////////////////////////////////////////////////////////////////////////
// Variables
// state of SPI transfer: 0 = idle, > 0 = transmiting, < 0 = waking up
s32 QT411State = QT411SIdle;
u8 QT411OutBuffer = 0;
u8 QT411InBuffer = 0;
////////////////////////////////////////////////////////////////////////
// Functions
void KEYTAR_QT411_Timer(void)
{
// we need to wait until the chip is ready
if (QT411State == -1)
{
// check if device is ready
if (MIOS32_BOARD_J5_PinGet(0) > 0)
{
// start transmission
MIOS32_SPI_RC_PinSet(2, 1, 0);
QT411State = 1;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] Slave Select => low");
#endif
}
}
else
if (QT411State > 0)
{
switch (QT411State)
{
case 1: {
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] starting transmission");
#endif
MIOS32_SPI2_SET_SCLK_0;
QT411InBuffer = 0;
MIOS32_SPI2_SET_MOSI(QT411OutBuffer & 0x80); // D7
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 1 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 2: {
MIOS32_SPI2_SET_SCLK_1;
QT411InBuffer |= MIOS32_SPI2_GET_MISO ? 0x80 : 0x00;
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 2 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 3: {
MIOS32_SPI2_SET_SCLK_0;
MIOS32_SPI2_SET_MOSI(QT411OutBuffer & 0x40); // D6
QT411State++;
break;
}
case 4: {
MIOS32_SPI2_SET_SCLK_1;
QT411InBuffer |= MIOS32_SPI2_GET_MISO ? 0x40 : 0x00;
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 3 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 5: {
MIOS32_SPI2_SET_SCLK_0;
MIOS32_SPI2_SET_MOSI(QT411OutBuffer & 0x20); // D5
QT411State++;
break;
}
case 6: {
MIOS32_SPI2_SET_SCLK_1;
QT411InBuffer |= MIOS32_SPI2_GET_MISO ? 0x20 : 0x00;
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 4 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 7: {
MIOS32_SPI2_SET_SCLK_0;
MIOS32_SPI2_SET_MOSI(QT411OutBuffer & 0x10); // D4
QT411State++;
break;
}
case 8: {
MIOS32_SPI2_SET_SCLK_1;
QT411InBuffer |= MIOS32_SPI2_GET_MISO ? 0x10 : 0x00;
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 5 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 9: {
MIOS32_SPI2_SET_SCLK_0;
MIOS32_SPI2_SET_MOSI(QT411OutBuffer & 0x08); // D3
QT411State++;
break;
}
case 10: {
MIOS32_SPI2_SET_SCLK_1;
QT411InBuffer |= MIOS32_SPI2_GET_MISO ? 0x08 : 0x00;
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 6 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 11: {
MIOS32_SPI2_SET_SCLK_0;
MIOS32_SPI2_SET_MOSI(QT411OutBuffer & 0x04); // D2
QT411State++;
break;
}
case 12: {
MIOS32_SPI2_SET_SCLK_1;
QT411InBuffer |= MIOS32_SPI2_GET_MISO ? 0x04 : 0x00;
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 7 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 13: {
MIOS32_SPI2_SET_SCLK_0;
MIOS32_SPI2_SET_MOSI(QT411OutBuffer & 0x02); // D1
QT411State++;
break;
}
case 14: {
MIOS32_SPI2_SET_SCLK_1;
QT411InBuffer |= MIOS32_SPI2_GET_MISO ? 0x02 : 0x00;
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 8 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 15: {
MIOS32_SPI2_SET_SCLK_0;
MIOS32_SPI2_SET_MOSI(QT411OutBuffer & 0x01); // D0
QT411State++;
break;
}
case 16: {
MIOS32_SPI2_SET_SCLK_1;
QT411InBuffer |= MIOS32_SPI2_GET_MISO ? 0x01 : 0x00;
QT411State++;
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] 9 - Buffer: %x %d", QT411InBuffer, QT411InBuffer);
#endif
break;
}
case 17: {
// This is only used to create a 60us period between the
// end of a byte and the falling edge of the RC line
QT411State++;
break;
}
case 18: {
// Byte complete, go back to idle
QT411State = QT411SIdle;
// set SS high
MIOS32_SPI_RC_PinSet(2, 1, 1);
#if DEBUG_VERBOSE_LEVEL >= 2
DEBUG_MSG("[KEYTAR_QT411] Transmission complete. result: %x", QT411InBuffer);
#endif
break;
}
}
}
}
This is what’s supposed to happen: The Pins are initialised as 5V outputs (Open drain. BTW the resistors are stuffed), except for the MISO pin, which is set up as input (with internal and external pullup - should be no problem). I start sending data by putting it into the buffer and setting the state to -1 = waiting for wake up. The timer runs every 30us, waiting until the “data ready” line is high. When this happens, the RC1 line is held low, the state is set to 1 and the timer routine is left. On the next timer calls (each being 30us later) the timer runs through the soft-spi steps, putting data on the line when the clock is low and reading data from the line, when the clock is high. At the end of the transmission, the state is reset and RC is set to high. But what’s really happening? I have no idea. I always get 255 as a result of a transmission. And I have no way to check the data lines but an LED connected to them. However, MISO is high until i start a transmission. Form there on, it is low until i reboot the core. The output of the debug messages is:
[21251.788] [KEYTAR_QT411]sending...
[21251.788] [KEYTAR_QT411] Slave Select => low
[21251.788] [KEYTAR_QT411] starting transmission
[21251.788] [KEYTAR_QT411] 1 - Buffer: 0 0
[21251.789] [KEYTAR_QT411] 2 - Buffer: 80 128
[21251.790] [KEYTAR_QT411] 3 - Buffer: c0 192
[21251.790] [KEYTAR_QT411] 4 - Buffer: e0 224
[21251.790] [KEYTAR_QT411] 5 - Buffer: f0 240
[21251.791] [KEYTAR_QT411] 6 - Buffer: f8 248
[21251.791] [KEYTAR_QT411] 7 - Buffer: fc 252
[21251.792] [KEYTAR_QT411] 8 - Buffer: fe 254
[21251.792] [KEYTAR_QT411] 9 - Buffer: ff 255
[21251.794] [KEYTAR_QT411] Transmission complete. result: ff
[21251.794] [KEYTAR_QT411]sending ok
[21251.794] [KEYTAR_QT411]got data: 255
My guess: The io Pins are not configured properly. I’veno idea about the IO stuff of the STM32 so far and the fact, that the result is alays 0xFF looks like an IO configuration error.
So my question is: what’s wrong here and is there a better solution for 40kHz SPI an J19?
Thenk you all,
Bääääär