priority question

Discussion to talk about software related topics only.
Post Reply
cnth98
Posts: 14
Joined: Wed Dec 01, 2010 8:15 am

priority question

Post by cnth98 »

How to prevent higher priority tasks such as http task from interrupting spi multi-bytes transfer of the lower priority task called by UserMain()?
User avatar
tod
Posts: 587
Joined: Sat Apr 26, 2008 8:27 am
Location: Southern California
Contact:

Re: priority question

Post by tod »

Look at your nburn\examples\RTOS\OSCrit folder. The wiki example applications page briefly describes all the example code.
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: priority question

Post by lgitlitz »

What SPI driver are you using?
If you are using the QSPI.h driver then the transfer will not be interrupted because this driver is interrupt based. In this driver 32 bytes are loaded into a hardware SPI buffer and transferred. After the transfer completes an interrupt is triggered to the CPU. In this interrupt routine data is exchanged from the hardware buffer and then SPI transferring resumes. Since this all the data transfer occurs in an interrupt routine it will run over any task priority. This is the type of driver you should use if you do not want a higher level task to stop the QSPI transfer.
The SD Card uses a different polling based SPI driver found in mmc_mcf.cpp. This works by the code running in a loop and feeding the hardware buffer while the transfer is active. The benefit of this driver is that the transfer never pauses to load the hardware buffer and effective throughput is higher. The negative of this type of driver is that it runs at the task level and requires 100% CPU time so any task switching will halt the transfer.
cnth98
Posts: 14
Joined: Wed Dec 01, 2010 8:15 am

Re: priority question

Post by cnth98 »

Yes, I'm using the QSPI.h driver to the eeprom and rtclock, calling from UserMain() loop periodically. The application runs well by itself. But has problem after accessing the web pages that also read/store data to the eeprom by using the QSPI functions.
My subroutine is :

. . .
//initTxrxEepBuf(0);
txEepBuf[0] = 3; // read cmd
txEepBuf[1] = (addr >> 16) & 0x000000ff; // adr
txEepBuf[2] = (addr >> 8) & 0x000000ff;
txEepBuf[3] = addr & 0x000000ff;
CS_EEP = 0; // enable cs eeprom
ret = QSPIStart(txEepBuf, rxEepBuf, nByte+4, &QSPI_SEM); // Send data via QSPI
if(OSSemPend( &QSPI_SEM, 2 )==OS_TIMEOUT) // Wait 100ms for QSPI to complete
eepFlag = EEP_ERR;
else eepFlag = EEP_OK;
CS_EEP = 1; // disable cs eeprom
...

I believe the QSPI library routines are non-interrupted. But could the http server interrupts after the chip select and before the QSPIStart?
greengene
Posts: 164
Joined: Wed May 14, 2008 11:20 am
Location: Lakeside, CA

Re: priority question

Post by greengene »

oh, you betcha!
the most common way to protect the integrity of the spi is to put a global semaphore
around your spi accesses. (similarly for i2c.) there are quite a few posts on here about
that - search on: spi semaphore.

pend
cs
qspi
cs
post
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: priority question

Post by lgitlitz »

cnth98,
I thought you were having a problem with your transfer being stalled, I didn't realize you had multiple tasks interfacing with the peripheral. Greengene is correct here, the QSPI.h driver is not thread safe. What you need to do to make it thread safe is put an OS object pend before you change any QSPI configurations or assert the chip select. You also need to post to that OS object after you de-assert the chip select. Look at the following posts:
http://forum.embeddedethernet.com/viewt ... ?f=5&t=147
http://forum.embeddedethernet.com/viewt ... &view=next

Another option is to have only a single task using QSPI. Then have your other tasks interact with the QSPI task when they want to send or receive data from an external peripheral.

-Larry
v8dave
Posts: 333
Joined: Thu Dec 31, 2009 8:31 pm

Re: priority question

Post by v8dave »

One thing that I ended up having to do was to change the libraries, even though the second link from Larry shows that I managed without this. It seems that the FFS uses different SPI speeds and this was causing my touch screen driver to fail.

I ended up having to use a CriticalSection and some code to init the SPI each call instead and this meant re-writing some of the libraries using SPI to allow me to setup the SPI each call so that the correct speed was being used.

This has worked flawlessly on 2 projects now.

Just something to be aware of if you decide to use the SPI for you own hardware.

Dave...
cnth98
Posts: 14
Joined: Wed Dec 01, 2010 8:15 am

Re: priority question

Post by cnth98 »

Hi Dave,
We studied your code. And still have some doubt in my application: In UserMain loop, it calls a subroutine that uses the qspi library to read clock and save data to eeprom. If the http server comes in and also need to read/write the eeprom at the same time, will it see the semaphore set by UserMain loop and say ok I let you finish what you're doing before I go on to do mine? http://forum.embeddedethernet.com/posti ... &f=5&t=931#
v8dave
Posts: 333
Joined: Thu Dec 31, 2009 8:31 pm

Re: priority question

Post by v8dave »

Hi there,

This is some of the code I used. Based on the recommendation from Netburner, what I did was put an OSCritEnter in the routine that sets the CHIP select for the device I want to communicate with. The OSCritLeave goes in the release call for chip select. Here is the code for it.

Code: Select all

void ts_spi_cs_hi()
{
	J2[40] = 1;

	OSCritLeave(&ShareQSPI);
}

Code: Select all

void ts_spi_cs_lo()
{
	OSCritEnter(&ShareQSPI, 0);

	QSPIInit(1000000, 8, 0x0F, 1, 0, 0, TRUE, 0x00, 0x00); // Set touch screen SPI rate

	J2[40] = 0;
}
You can see from the CHIP Select LOW call, I set the speed of the SPI at the same time because the SPI driver for the SD card changes the speed.

In the initialisation I make this call to initialise the critical section. You need to extern the variable used as it is defined elsewhere.

Code: Select all

 OSCritInit(&ShareQSPI);
Now, in mmc_mcf I added the following variables.

Code: Select all

OS_CRIT ShareQSPI;
unsigned long spi_baud_rate = 100000;	// Saved rate
Then the modified functions are as follows:

Code: Select all

int spi_init (void)
{
  OSCritEnter(&ShareQSPI, 0);		// Need this here as the spi_cs_hi call will call leave

  MMC_BaseInit();
  spi_cs_hi();

#ifndef SD_IRQ_QSPI
  QWR=0x9000;		/* stop + active low */
  QMR=0xC0FF;		/* Master mode */
  QDLYR=0;
  QAR=0x20;
  for (volatile int i=0;i<16;QDR=0x8B00,i++);

#else

  OSSemInit(&SD_QSPI_SEM, 0);  //initialize interrupt semaphores
  return QSPIInit( /*Baud*/ 100000, /*QueueBitSize*/8, /*CS*/ 0xF, /*CSPol*/ 0x1,
                   /*ClkPolarity*/0x0, /*ClkPhase*/ 0x0, /*DoutHiz*/ TRUE);
#endif

  return 0;
}

/*-------------------------------------------------------------------
 Set SPI chip select low
 --------------------------------------------------------------------*/
#ifdef SD_SHARES_SPI
   void _spi_cs_lo( void )
#else /* #ifndef SD_SHARES_SPI */
   void spi_cs_lo( void )
#endif /* #ifndef SD_SHARES_SPI */
{
  // J2[35] = 0;

   OSCritEnter(&ShareQSPI, 0);
   QSPIInit( /*Baud*/ 100000, /*QueueBitSize*/8, /*CS*/ 0xF, /*CSPol*/ 0x1,
                      /*ClkPolarity*/0x0, /*ClkPhase*/ 0x0, /*DoutHiz*/ TRUE);
   spi_set_baudrate(spi_baud_rate);	// Set the last rate we used

#if defined FAT_CONF_5270
   #if(defined SB70LC || defined SB700EX )
	  sim.gpio.pclrr_qspi = ~0x08;
   #elif PK70
      sim.gpio.pclrr_datal = ~0x10;
   #elif defined MOD5234
      sim.gpio.pclrr_etpu = ~0x01;
   #else
      sim.gpio.pclrr_timer = ~0x20;
   #endif
#elif defined FAT_CONF_5282
   sim.gpio.clrqs = ~0x20;
#elif defined FAT_CONF_5272
   sim.pdcnt |= 0x30;   // QSPI_CS2 enabled
#endif
}

/*-------------------------------------------------------------------
 Set SPI chip select high
 --------------------------------------------------------------------*/
#ifdef SD_SHARES_SPI
   void _spi_cs_hi( void )
#else /* #ifndef SD_SHARES_SPI */
   void spi_cs_hi( void )
#endif /* #ifndef SD_SHARES_SPI */
{
// J2[35] = 1;

#if defined FAT_CONF_5270
   #if(defined SB70LC || defined SB700EX )
	sim.gpio.ppdsdr_qspi = 0x08;

   #elif PK70
      sim.gpio.ppdsdr_datal = 0x10;
   #elif defined MOD5234
      sim.gpio.ppdsdr_etpu = 0x01;
   #else
      sim.gpio.ppdsdr_timer = 0x20;
   #endif
#elif defined FAT_CONF_5282
   sim.gpio.portqsp = 0x20;
#elif defined FAT_CONF_5272
   sim.pdcnt &= ~(0x0030);   // QSPI_CS2 Hiz
#endif

   spi_baud_rate = spi_get_baudrate();

   OSCritLeave(&ShareQSPI);
}
Hope this helps more but if you have any more question please do ask.

Cheers,
Dave...
cnth98
Posts: 14
Joined: Wed Dec 01, 2010 8:15 am

Re: priority question

Post by cnth98 »

I appreciate your help. It's not a problem for me to have the clock and EEProm to share the same spi bus. It's the sub-routine called by UserMain() that access the EEP got interrupted by the http server that's also accessing the EEP.

I did try to put the OSCritEnter() and OSCritExit() around the read/write code. But the application is trapped in ucos.c when the http server wants to read 2000 records from the eeprom. Without putting the Critical section in, it wouldn't trap.

Code: Select all


 static OS_CRIT crtWrtSec; // critical write section
   ...
	
    OSCritInit(&crtWrtSec);
    OSCritEnter(&crtWrtSec, 0);

    if(!isEepReady()){ 
    	OSCritLeave(&crtWrtSec);
    	return 2;
    }
    txEepBuf[0] = 6;  // cmd write enable
    CS_EEP = 0;        // enable eep
    ret = QSPIStart(txEepBuf, rxEepBuf, 1, &QSPI_SEM); // Send data via QSPI
    if(OSSemPend( &QSPI_SEM, 2 )==OS_TIMEOUT)   // Wait 100ms for QSPI to complete
    	eepFlag = EEP_ERR;
    CS_EEP = 1;

    txEepBuf[0] = 2;  // write eep cmd
    txEepBuf[1] = (addr >> 16) & 0x000000ff;  // load the addr
    txEepBuf[2] = (addr >> 8) & 0x000000ff;
    txEepBuf[3] = addr & 0x000000ff;
    
    CS_EEP = 0;   // enable eep
    ret = QSPIStart(txEepBuf, rxEepBuf, nByte+4, &QSPI_SEM); // Send data via QSPI
    if(OSSemPend( &QSPI_SEM, 2 )==OS_TIMEOUT) // Wait 100ms for QSPI to complete
    	eepFlag = EEP_ERR;
    else eepFlag = EEP_OK;
    CS_EEP = 1;   // disable eep

    OSCritLeave(&crtWrtSec);
Post Reply