Bääääär Posted April 21, 2011 Report Posted April 21, 2011 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 Quote
TK. Posted April 21, 2011 Report Posted April 21, 2011 Hi, 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? FreeRTOS controls the timesplices, it performs preemptive multitasking (see also this tutorial. However, using a timer is a better idea in this case, so you are already on the right route. Just for interest: why are you not using J16 with HW based SPI? Does "waiting" slow down my application and "eat" cycles, or does it simply do other things while waiting? another task could interrupt the task which generates the bitstream for J19, FreeRTOS guarantees that each task will be serviced in 1 mS On the other hand this means, that the bitstream generation will be slowed down... Again: using a timer is a good idea if HW based SPI at J16 can't be used. 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. First idea: which SPI parameters are required for the slave? Clock Phase, clock polarity? There are four possibilities, and if you chose the wrong one, data transfer will be corrupted. In your current code, data is set with the falling clock edge, and data is read with the rising clock edge - does this comply with the datasheet of your SPI device? Best Regards, Thorsten. Quote
Bääääär Posted April 22, 2011 Author Report Posted April 22, 2011 Just for interest: why are you not using J16 with HW based SPI? The main reason is, there is a special sleep mode of the device, which requires a strange way of communication. I'm not sure, if this can be achieved with HW SPI. For first I want to implement the normal mode (without sleep) in Software SPI to see, if it works. I could update it later on to support sleep mode. (However, due to my problems with software SPI I'm really starting to think about if it was better to go the HW way now...) another task could interrupt the task which generates the bitstream for J19, FreeRTOS guarantees that each task will be serviced in 1 mS On the other hand this means, that the bitstream generation will be slowed down... Again: using a timer is a good idea if HW based SPI at J16 can't be used. Well that could be a problem... From the datasheet I can see, that a clock cycle must never be longer than 100us. So I probably need to switch the timer to highest priority once transfer has begun to avoid interruptions. First idea: which SPI parameters are required for the slave? Clock Phase, clock polarity? There are four possibilities, and if you chose the wrong one, data transfer will be corrupted. In your current code, data is set with the falling clock edge, and data is read with the rising clock edge - does this comply with the datasheet of your SPI device? See here: The SPI interface is a five-wire slave-only type; timings are found in Figure 3-1. The phase clocking is as follows: Clock rate: 5kHz min, 40kHz max Bit length & order: 8 bits, MSB shifts first Data Ready DRDY: Low from QT inhibits host Slave Select /SS: Negative level frame from host Input data read on: Rising edge of CLK from host Data out changes on: Falling edge of CLK from host Clock idle: High Looks fine so far. What made me think of an IO error is: However, MISO is high until I start a transmission. Form there on, it is low until I reboot the core. MISO is low since the first transmission (don't know if it goes low before or after the first transmission though). It's low and I get "high". That can't be correct. Maybe I should try to use hardware SPI instead... And leave out sleep mode if neccessary... I need to set a prescaler before and after each transmission to get slow SPI for the QT411 and fast SPI for the other devices that are connected to J16, right? Thanks for your help, Bääääär Quote
Bääääär Posted April 22, 2011 Author Report Posted April 22, 2011 I just found out that the prescaler for HW SPI can't be set low enough for 40kHz SPI. I'll have to go the SW way then... Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.