Response timing delay of spi read/write in extint1 high leve

what i want is, to exchange pcm-datas between a Q2687RD Modual and a hispeed C8051F by SPI.
pcm-data was PCM_8K_16B, so, 16b*8k=128bK=16K Bytes, for read and write, total data would be 32KB, so I use SPI to transfer
datas.

C8051F(worked @ 90Mhz) genarate a intr @ extintr pin ON Q2687RD in a freqency of 1000Hz square wave (pcm-datas would be 16b*8=128b=16B), in the intr procedure of Q26, exchange the datas by SPI read and write(16Bytes each).
but my testing of some timing sequence and singal delay made is very difficulty.

C8051F(from silicon labs, really high speed C51) = 90MHz
Q26 CPU = 104Mhz(normal speed is 26Mhz)
Extint1 config={ ADL_EXTINT_SENSITIVITY_RISING_EDGE, DL_EXTINT_FILTER_BYPASS_MODE, 0, 0, NULL };
SPI uses SPI2 on Q26(SPI w/r in Extint1 high level interrupt procedure, w/r in low level would LOCK the spi).

a. test result 1 (test intr freq=5Hz, spi speed=130Kb)
(timing sequence and singal delay are from oscilloscope measurement)
Extint1 Period=200ms
spi(write first, 16bytes) start (first spi clock) delay to Extint1_rising(from C8051F IO pin)=betwen 400us–650us), few more than 650us.
spi(read, 16bytes) start (first spi clock) delay to spi(write)=betwen 170us–250us.
so, a complete spi write+read would almost 2.8ms.(data i/o tansfer almost be 2ms).

b. test result 2(test intr freq=5Hz, spi speed=2000Kb)
(timing sequence and singal delay are from oscilloscope measurement)
Extint1 config={ ADL_EXTINT_SENSITIVITY_RISING_EDGE, DL_EXTINT_FILTER_BYPASS_MODE, 0, 0, NULL };
Extint1 Period=200ms
spi(write first, 16bytes) start (first spi clock) delay to Extint1_rising=betwen 400us–650us, almost same as test1.
spi(read, 16bytes) start (first spi clock) delay to spi(write)=almost same as test1.
so, a complete spi write+read would almost 1.33ms(max), normal data i/o tansfer be 700us-1ms).

c. test intr freq=1000Hz often made the Q26 WDT reset.

so, I’m surprising,
1 why the big responsing time delay of extint1 intr procedure, it’s almost more than 400us…, can and how this improved?
2 How can I use the SPI do a 32KB/sec datas transfer on Q26 with a High speed C51.

Thanks for every suggestions. :slight_smile:

My source codes followed…

#include “adl_global.h”
#include “generated.h”

#include “adl_extint.h”
#include “adl_irq.h”

// Global variables
#define ONE 1
#define ZERO 0
#define GPIO_OUTPUT_PIN 20
#define GPIO_CONFIG_LENGTH 1
// SPI Subscription data
#define SPI_ID1 1
#define SPI_ID2 2
#define SPI_CS1 31
#define SPI_CS2 35

//#define MySel_SPI1 // SPI1
#define MySel_SPI2 // SPI2

#ifdef MySel_SPI2
#define SPI_ID SPI_ID2
#define SPI_CS SPI_CS2
#else
#define SPI_ID SPI_ID1
#define SPI_CS SPI_CS1
#endif

adl_busSPISettings_t MySPIConfig =
{
//102, // 130Kb
6, // 2Mb
ADL_BUS_SPI_CLK_MODE_0, // Mode 0 clock
ADL_BUS_SPI_ADDR_CS_GPIO, // Use a GPIO to handle the Chip Select signal
ADL_BUS_SPI_CS_POL_LOW, // Chip Select active in low state
ADL_BUS_SPI_MSB_FIRST, // Data are sent MSB first
ADL_IO_GPIO | SPI_CS, // Use GPIO 31 to handle the Chip Select signal
ADL_BUS_SPI_LOAD_UNUSED, // LOAD signal not used
ADL_BUS_SPI_DATA_UNIDIR, //ADL_BUS_SPI_DATA_BIDIR, // 2 Wires configuration
ADL_BUS_SPI_MASTER_MODE, // Master mode
ADL_BUS_SPI_BUSY_UNUSED //ADL_BUS_SPI_BUSY_UNUSED // BUSY signal not used
};

// Write/Read buffer sizes
#define WRITE_SIZE 32
#define READ_SIZE 32

// Access configuration structure
adl_busAccess_t AccessConfig = { 0, 0 };
adl_busAccess_t AccessConfigw = { 0xC1000000, 0xC1000000 }; // W:C1 85
adl_busAccess_t AccessConfigr = { 0x95000000, 0x95000000 }; // R:95 ??
adl_busAccess_t AccessConfigOn = { 0x02000000, 0x02000000 };
adl_busAccess_t AccessConfigOff = { 0x01000000, 0x01000000 };

// BUS Handles
s32 MySPIHandle;
adl_tmr_t* hMyTimer=NULL;
s32 hIrqMyTcu, hMyTcu;
s32 hVariSpeed_0;
s32 hIoMyGpio_20;

// Data buffers
u8 WriteBuffer [ WRITE_SIZE ], ReadBuffer [ READ_SIZE ];

// use the PIN0 for the Ext Int
#define EXTINT_PIN0 0
#define EXTINT_PIN1 1

// ExtInt service handle
s32 ExtIntHandle;

// IRQ service handle
s32 IrqHandle;

// ExtInt configuration: both edge detection without filter
adl_extintConfig_t extintConfig =
{ ADL_EXTINT_SENSITIVITY_RISING_EDGE, ADL_EXTINT_FILTER_BYPASS_MODE, 0, 0, NULL };
//{ ADL_EXTINT_SENSITIVITY_BOTH_EDGE, ADL_EXTINT_FILTER_BYPASS_MODE, 0, 0, NULL };

unsigned char CntrExt = 0, CntrTmr = 0, CntrTcu = 0;

// ExtInt interruption handler
bool MyExtIntHandler ( adl_irqID_e Source,
adl_irqNotificationLevel_e NotificationLevel,
adl_irqEventData_t * Data )
{
// Read the input status
s32 s32Res_r, s32Res_w;
adl_extintInfo_t Status, Status2, *AutoReadStatus;
u32 LoopsNb;

// Input status can also be obtained from the auto read option.
AutoReadStatus = ( adl_extintInfo_t * ) (Data->SourceData);
adl_extintRead ( ExtIntHandle, &Status );
Status2 = *AutoReadStatus; // This value NOT show the real PinState

#define EN_EXTINT1_0
#ifdef EN_EXTINT1_0
if (CntrExt>4)
{
LoopsNb = 16;
if (CntrExt &1 )
{
//s32Res_w = adl_busWrite ( MySPIHandle, &AccessConfigOn, 8, WriteBuffer );
// infact datas are 8bits in WriteBuffer, so we can reduce 1/2 of datas write
// the read would be the same
s32Res_w = adl_busWrite ( MySPIHandle, &AccessConfigw, LoopsNb, WriteBuffer );
s32Res_r = adl_busRead ( MySPIHandle, &AccessConfigr, LoopsNb, ReadBuffer );
//s32Res_r = OK;
TRACE( ( 2, “EI :%3d=[%d %d]ON”, CntrExt, NotificationLevel, (CntrExt &1), s32Res_w, s32Res_r ) );
} else
{
//s32Res_r = adl_busWrite ( MySPIHandle, &AccessConfigOff, 8, ReadBuffer );
s32Res_w = adl_busWrite ( MySPIHandle, &AccessConfigw, LoopsNb, WriteBuffer );
s32Res_r = adl_busRead ( MySPIHandle, &AccessConfigr, LoopsNb, ReadBuffer );
//s32Res_w = OK;
TRACE( ( 2, “EI :%3d=[%d %d]Of”, CntrExt, NotificationLevel, (CntrExt &1), s32Res_w, s32Res_r ) );
}
}
#else
TRACE( ( 2, “EI :%3d=(%d)(%d,%d)”, CntrExt, NotificationLevel, Status.PinState, Status2.PinState ) );
#endif

CntrExt++;
return FALSE;
//  TRUE :  enable High level handler notification
//  FALSE: disable High level handler notification

}
//
/* Function : cbTcuIrqHandler /
/
Scope : ADL Interrupt service low level handler /
/
Return : TRUE to enable High level handler notification /
/
FALSE to disable High level handler notification */
/
/
bool cbTcuIrqHandler ( adl_irqID_e Source, adl_irqNotificationLevel_e NotificationLevel, adl_irqEventData_t * Data )
{
s32 s32Res_r, s32Res_w;
adl_extintInfo_t Status;
u32 LoopsNb;

adl_extintRead ( ExtIntHandle, &Status );
adl_ioDefs_t GpioConfigH = ADL_IO_GPIO | GPIO_OUTPUT_PIN | ADL_IO_DIR_OUT | ADL_IO_LEV_HIGH;
adl_ioDefs_t GpioConfigL = ADL_IO_GPIO | GPIO_OUTPUT_PIN | ADL_IO_DIR_OUT | ADL_IO_LEV_LOW;

//TRACE( ( 3, "        Entering TCU Interrupt %d", CntrTcu ) );

//#define EN_TCU_0
#ifdef EN_TCU_0
if (CntrTcu>4)
{
if (CntrTcu &1 )
{
s32Res_w = adl_busWrite ( MySPIHandle, &AccessConfigOn, 0, WriteBuffer );
s32Res_r = OK;
TRACE( ( 3, “TCU :%3d=[%d %d]ON”, CntrTcu, NotificationLevel, (CntrTcu &1), s32Res_w, s32Res_r ) );
} else
{
s32Res_r = adl_busWrite ( MySPIHandle, &AccessConfigOff, 0, ReadBuffer );
s32Res_w = OK;
TRACE( ( 3, “TUC :%3d=[%d %d]Of”, CntrTcu, NotificationLevel, (CntrTcu &1), s32Res_w, s32Res_r ) );
}
}
#else
/if (CntrTcu>4)
{
if (CntrTcu &1 )
{
LoopsNb = ZERO;
s32Res_r = adl_ioWrite ( hIoMyGpio_20, GPIO_CONFIG_LENGTH, &GpioConfigH );
while ( 30 > LoopsNb ) LoopsNb++;
// Write on the IO to cause the EXTINT
s32Res_w = adl_ioWrite ( hIoMyGpio_20, GPIO_CONFIG_LENGTH, &GpioConfigL );
}
}
/
//TRACE( ( 3, “TUC :%3d=(%d)(%d TCU)”, CntrTcu, CntrTcu &1, hIoMyGpio_20 ) );
#endif
//TRACE( (3, " Leaving TCU Interrupt %d", CntrTcu ) );
CntrTcu++;
return FALSE;
} // cbTcuIrqHandler

void timer_Handler ( u8 ID, void * Context )
{
s32 s32Res_r, s32Res_w;
adl_extintInfo_t Status;

adl_extintRead ( ExtIntHandle, &Status );

//TRACE( ( 1, "TMR %3d %d >>....", CntrTmr, Status ) );

//#define EN_TIMER_0
#ifdef EN_TIMER_0
if (CntrTmr>4)
{
if (CntrTmr &1 )
{
s32Res_w = adl_busWrite ( MySPIHandle, &AccessConfigOn, 0, WriteBuffer );
s32Res_r = OK;
TRACE( ( 4, “TMR :%3d=[%d]ON”, CntrTmr, (CntrTmr &1), s32Res_w, s32Res_r ) );
} else
{
s32Res_r = adl_busWrite ( MySPIHandle, &AccessConfigOff, 0, ReadBuffer );
s32Res_w = OK;
TRACE( ( 4, “TMR :%3d=[%d]Of”, CntrTmr, (CntrTmr &1), s32Res_w, s32Res_r ) );
}
}
#else
//TRACE( ( 4, “TMR :%3d=( )(%d TIMER)”, CntrTmr, Status.PinState ) );
#endif
//TRACE( ( 1, “TMR %3d %d …>>”, CntrTmr, Status ) );
CntrTmr++;
}

void init_spi_2 ( void )
{
// Local variables
#define INIT_IOX
#ifdef INIT_IO
s32 s32Res_r, s32Res_w;
#endif
u32 u32Val = 0;
// Subscribe to the SPI1 BUS
MySPIHandle = adl_busSubscribe ( ADL_BUS_ID_SPI, SPI_ID, &MySPIConfig );
TRACE( ( 1, “adl_busSubscribe(%d)=(hBus=%d)”, SPI_ID, MySPIHandle ) );

// Configure the Address length to 0 (rewrite the default value)
adl_busIOCtl ( MySPIHandle, ADL_BUS_CMD_SET_ADD_SIZE, &u32Val );
u32Val = 8;
adl_busIOCtl ( MySPIHandle, ADL_BUS_CMD_SET_OP_SIZE,  &u32Val );
adl_busIOCtl ( MySPIHandle, ADL_BUS_CMD_SET_DATA_SIZE, &u32Val );

// Write 5 bytes set to '0' on the SPI & I2C bus
// wm_memset ( WriteBuffer, WRITE_SIZE, 0 ); // Are the params RIGHT?
//wm_memset ( WriteBuffer, 0, WRITE_SIZE );  // This should be right
//wm_memset ( ReadBuffer, 0, WRITE_SIZE );

#ifdef INIT_IO
s32Res_w = adl_busWrite ( MySPIHandle, &AccessConfig, WRITE_SIZE, WriteBuffer );
s32Res_r = adl_busRead ( MySPIHandle, &AccessConfig, READ_SIZE, ReadBuffer );
TRACE( ( 1, “INIT:%d=(%d,%d)”, MySPIHandle, s32Res_w, s32Res_r ) );
#endif
}
void init_extint_1 ( void )
{
u32 OneShotMode = 0;
s32 s32Result;
adl_extintCapabilities_t My_ExtInt_Capa;

adl_extintGetCapabilities ( &My_ExtInt_Capa );

// Test if the WCPU have Ext Int pin
if ( My_ExtInt_Capa.NbExternalInterrupt >= 1 )
{
	// Subscribes to the IRQ service
	//IrqHandle = adl_irqSubscribe ( MyExtIntHandler, ADL_IRQ_NOTIFY_HIGH_LEVEL, 1, ADL_IRQ_OPTION_AUTO_READ );
	IrqHandle = adl_irqSubscribe ( MyExtIntHandler, ADL_IRQ_NOTIFY_HIGH_LEVEL, 1, ADL_IRQ_OPTION_PRE_ACKNOWLEDGEMENT );
	TRACE( ( 1, "adl_irqSubscribe(L)=(hIrq=%d)", IrqHandle ) );

	ExtIntHandle = adl_extintSubscribe ( EXTINT_PIN1, 0, IrqHandle, &extintConfig );
	TRACE( ( 1, "adl_extintSubscribe(EXT_ID:%d)=(hExtInt=%d)", EXTINT_PIN1, ExtIntHandle ) );

	if( ExtIntHandle > 0 )
	{
		OneShotMode = 0;
		s32Result = adl_extintGetConfigExt( ExtIntHandle, ADL_EXTINT_EXTCONFIG_ONE_SHOT_MODE, &OneShotMode);
		TRACE( ( 1, "adl_extintGetConfigExt(ONE_SHOT=%d)=%d", OneShotMode, s32Result ) );
		// Set the EXT INT in one shot mode
		if( !OneShotMode )
		{
			OneShotMode = FALSE;//TRUE;
			s32Result = adl_extintSetConfigExt( ExtIntHandle, ADL_EXTINT_EXTCONFIG_ONE_SHOT_MODE, OneShotMode );
		}
	}
}

}

void init_tcu ( void )
{
adl_tcuTimerSettings_t TCUSettings = { { 100, ADL_TCU_TIMER_UNIT_MS }, TRUE };
//hIrqMyTcu = adl_irqSubscribe ( cbTcuIrqHandler, ADL_IRQ_NOTIFY_LOW_LEVEL, 0, ADL_IRQ_OPTION_PRE_ACKNOWLEDGEMENT );
hIrqMyTcu = adl_irqSubscribe ( cbTcuIrqHandler, ADL_IRQ_NOTIFY_HIGH_LEVEL, 1, ADL_IRQ_OPTION_PRE_ACKNOWLEDGEMENT );
TRACE( ( 1, “adl_irqSubscribe(L)=(hIrq_tcu=%d)”, hIrqMyTcu ) );
//hMyTcu = adl_tcuSubscribe ( ADL_TCU_ACCURATE_TIMER, hIrqMyTcu, 0, &TCUSettings, NULL );
hMyTcu = adl_tcuSubscribe ( ADL_TCU_ACCURATE_TIMER, 0, hIrqMyTcu, &TCUSettings, NULL );
TRACE( ( 1, “adl_tcuSubscribe(L, period=%dms)=(hTcu=%d)”, TCUSettings.Duration.DurationValue, hMyTcu ) );
adl_tcuStart ( hMyTcu );
}

void init_varispeed( void )
{
s32 s32Res;
//adl_vsMode_e CkMode_Nor = ADL_VS_MODE_STANDARD ; // CLK=26MHz
adl_vsMode_e CkMode_High; // = ADL_VS_MODE_BOOST ; // CLK=26*4=104MHz

hVariSpeed_0 = adl_vsSubscribe ();
TRACE( ( 1, "adl_vsSubscribe()=(hVariSpeed=%d)", hVariSpeed_0 ) );
s32Res = adl_vsGetClockMode (hVariSpeed_0, &CkMode_High);
TRACE( ( 1, "adl_vsSetClockMode(VS_MODE=%d)=(%d)", CkMode_High, s32Res ) );
CkMode_High = ADL_VS_MODE_BOOST;
s32Res = adl_vsSetClockMode (hVariSpeed_0, CkMode_High);
TRACE( ( 1, "adl_vsSetClockMode(BOOST=104MHz)=(%d)", s32Res ) );
s32Res = adl_vsGetClockMode (hVariSpeed_0, &CkMode_High);
TRACE( ( 1, "adl_vsSetClockMode(VS_MODE=%d)=(%d)", CkMode_High, s32Res ) );

}

void init_gpio(void)
{
adl_ioDefs_t GpioConfig = ADL_IO_GPIO | GPIO_OUTPUT_PIN | ADL_IO_DIR_OUT | ADL_IO_LEV_LOW;
hIoMyGpio_20 = adl_ioSubscribe ( ONE, &GpioConfig, ZERO, ZERO, ZERO );
TRACE( ( 1, “adl_ioSubscribe(IO_PIN:%d)=(hIo=%d)”, GPIO_OUTPUT_PIN, hIoMyGpio_20 ) );
} // init_gpio

void final_all ( void )
{
// Un-subscribes from the ExtInt service
// Unsubscribe from subscribed BUS
adl_busUnsubscribe ( MySPIHandle );
adl_extintUnsubscribe ( ExtIntHandle );
adl_irqUnsubscribe (IrqHandle );
}

void main_task(void) {
// TODO Insert your task initialization code here
adl_InitType_e InitType = adl_InitGetType ();
TRACE( ( 1, “Application: Spi_io in extint”, InitType ) );
init_varispeed();
init_spi_2();
init_extint_1();
init_tcu();
init_gpio();

hMyTimer = adl_tmrSubscribe ( TRUE, 8, ADL_TMR_TYPE_100MS, timer_Handler );
TRACE( ( 1, "Application context diagnostic: %X", adl_ctxGetDiagnostic() ) );

}

by now, for the big delay, I have to change my design to use UART2/UART1 to exchange PCM-datas(this also down to 8Khz_8bit). 2*64Kb/sec, the uart can deal with it.

Anyone any suggestion for a faster responsing timing of SPI data exchang in an interrupt? From the test, other interrupt response delay would also like mine, No one mind it?