AnsweredAssumed Answered

Please can anyone point out why I am unable to get an SPI slave TX buffer empty interrupt in a blackfin bf59x?

Question asked by NuRichard on Aug 21, 2014
Latest reply on Sep 24, 2014 by NuRichard

Hello,

 

I am struggling to get my SPI slave to fill the TX buffer using DMA or simply using an interrupt service routine.  As far as I can tell no interrupt request is being generated when the SPI peripheral TX buffer is empty.  After simplifying the code down to the listing at the bottom I am unable to trigger the interrupt. What I think I am doing is:

* Leaving SPI0 status mapped to IVG7 as per the default

* Attaching an ISR to IVG7

* Enabling IVG7

* Enabling the SPIO0_STATUS interrupt source

* Configuring/Enabling SPI0

* Loading the SPI0 TX register with some data

* When-ever the ISR runs it should re-load the TX buffer with a different number

 

What I actually see is that the first byte is received by the master but after that only zero's are received and the ISR never appears to run / hit a break-point put inside the function.  If the SPI peripheral were not raising the interrupt request this would explain what was happening in this simplified case and when using DMA.

 

This is related to the Re: How to get a SPI slave deselected interrupt for a blackfin bf59x? question and has the input slave chip select being used as a GPIO (so that I can get an interrupt at the end of a unpredictable SPI exchange length when using DMA)

 

Thank you all for any suggestions you can provide,

Richard

 

 

#include <drivers/spi/adi_spi_reg_bf5xx.h>
#include <stdint.h>
#include <blackfin.h>


typedef enum {
  INTERRUPT_SYSTEM_PLL_WAKEUP = 0,
  INTERRUPT_SYSTEM_DMA_ERROR = 1,
  INTERRUPT_SYSTEM_PPI_ERROR = 2,
  INTERRUPT_SYSTEM_SPORT0_STATUS = 3,
  INTERRUPT_SYSTEM_SPORT1_STATUS = 4,
  INTERRUPT_SYSTEM_SPI0_STATUS = 5,
  INTERRUPT_SYSTEM_SPI1_STATUS = 6,
  INTERRUPT_SYSTEM_UART0_STATUS = 7,
  INTERRUPT_SYSTEM_DMA0 = 8,
  INTERRUPT_SYSTEM_DMA1 = 9,
  INTERRUPT_SYSTEM_DMA2 = 10,
  INTERRUPT_SYSTEM_DMA3 = 11,
  INTERRUPT_SYSTEM_DMA4 = 12,
  INTERRUPT_SYSTEM_DMA5 = 13,
  INTERRUPT_SYSTEM_DMA6 = 14,
  INTERRUPT_SYSTEM_DMA7 = 15,
  INTERRUPT_SYSTEM_DMA8 = 16,
  INTERRUPT_SYSTEM_PORTF_INTA = 17,
  INTERRUPT_SYSTEM_PORTF_INTB = 18,
  INTERRUPT_SYSTEM_TIMER0 = 19,
  INTERRUPT_SYSTEM_TIMER1 = 20,
  INTERRUPT_SYSTEM_TIMER2 = 21,
  INTERRUPT_SYSTEM_PORTG_INTA = 22,
  INTERRUPT_SYSTEM_PORTG_INTB = 23,
  INTERRUPT_SYSTEM_TWI = 24,
  INTERRUPT_SYSTEM_RESERVED0 = 25,
  INTERRUPT_SYSTEM_RESERVED1 = 26,
  INTERRUPT_SYSTEM_RESERVED2 = 27,
  INTERRUPT_SYSTEM_RESERVED3 = 28,
  INTERRUPT_SYSTEM_MDMA0 = 29,
  INTERRUPT_SYSTEM_MDMA1 = 30,
  INTERRUPT_SYSTEM_WATCHDOG = 31,
} INTERRUPT_SYSTEM;


typedef enum {
  INTERRUPT_HANDLER_7 = 7,
  INTERRUPT_HANDLER_8 = 8,
  INTERRUPT_HANDLER_9 = 9,
  INTERRUPT_HANDLER_10 = 10,
  INTERRUPT_HANDLER_11 = 11,
  INTERRUPT_HANDLER_12 = 12,
  INTERRUPT_HANDLER_13 = 13,
  INTERRUPT_HANDLER_14 = 14,
  INTERRUPT_HANDLER_15 = 15,
} INTERRUPT_HANDLER;


void interrupt_handler_enable(INTERRUPT_HANDLER h) {
  *pIMASK |= 1<<h;
}


void interrupt_handler_disable(INTERRUPT_HANDLER h) {
  *pIMASK &= ~(1<<h);
}


void interrupt_handler_set(INTERRUPT_HANDLER h, void (*f)(void)) {
  *((void * volatile *)(EVT0 + (EVT1-EVT0)*h)) = f;
}


void interrupt_system_enable(INTERRUPT_SYSTEM s) {
  *pSIC_IMASK0 |= (uint32_t)1<<s;
}


void interrupt_system_disable(INTERRUPT_SYSTEM s) {
  *pSIC_IMASK0 &= ~((uint32_t)1<<s);
}


bool interrupt_system_triggered(INTERRUPT_SYSTEM s) {
  return *pSIC_ISR0 & ((uint32_t)1<<s);
}


void interrupt_system_handler(INTERRUPT_SYSTEM s, INTERRUPT_HANDLER h) {
  volatile uint32_t* p = (volatile uint32_t *)(SIC_IAR0 + (SIC_IAR1-SIC_IAR0)*(s>>3)); //8 IAR values per register
  char shift = ((s & 7)*4); //Each value is 4 bits wide
  *p = (*p & ~(0xF << shift)) | ((h-7) << shift);
}


_Pragma("interrupt")
void nmi_handler(void);


_Pragma("interrupt")
void evx_handler(void);




volatile static uint8_t foo = 0x55;
_Pragma("interrupt")
static void irq_handler()
{
  if (!(*pSPI0_STAT & 0x8))
  {
  *pSPI0_TDBR = foo++;
  }
  *pSPI0_STAT = 0x56;
}


void spi_init(void)
{
  //interrupt_system_handler(INTERRUPT_SYSTEM_SPI0_STATUS, INTERRUPT_HANDLER_7);  // This is the default setting
  interrupt_handler_set(INTERRUPT_HANDLER_7, irq_handler);
  interrupt_handler_enable(INTERRUPT_HANDLER_7);
  interrupt_system_enable(INTERRUPT_SYSTEM_SPI0_STATUS);


  *pSPI0_CTL = ENUM_SPI_CTL_ZERO |
  ENUM_SPI_CTL_SIZE08 |
  ENUM_SPI_CTL_LSB_FIRST |
  ENUM_SPI_CTL_SCKMID |
  ENUM_SPI_CTL_SCKHI |
  ENUM_SPI_CTL_SLAVE |
  ENUM_SPI_CTL_MISO_EN |
  ENUM_SPI_CTL_ODM_DIS |
  ENUM_SPI_CTL_TIMOD01 |
  SPE;
  *pSPI0_TDBR = foo++;
}

Outcomes