Ejemplo n.º 1
0
/////////////////////////////////////////////////////////////////////////////
//! Outputs the Write Buffer Memory opcode/constant (8 bits) and data to 
//! write (8 bits) over the SPI.  
//!
//! EWRPT is incremented after the write.
//! \param[in] value Byte to write into the ENC28J60 buffer memory
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_MACPut(u8 value)
{
  s32 status = 0;

  CSN_0;
  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, WBM);
  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, value);
  CSN_1;

  return status;
}
Ejemplo n.º 2
0
/////////////////////////////////////////////////////////////////////////////
//! Sends the 8 bit BFS opcode/Address byte over the SPI and then sends 
//! the data in the next 8 SPI clocks
//!
//! This routine is almost identical to the MIOS32_ENC28J60_WriteReg() and
//! MIOS32_ENC28J60_BFCReg() functions.  It is separate to maximize speed.
//!
//! MIOS32_ENC28J60_BFSReg() must only be used on ETH registers.
//! \param[in] address 5 bit address of the register to modify. The top 3 bits must be 0
//! \param[in] data Byte to be used with the Bit Field Set operation
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_BFSReg(u8 address, u8 data)
{
  s32 status = 0;

  CSN_0;
  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, BFS | address);
  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, data);
  CSN_1;

  return status;
}
Ejemplo n.º 3
0
/////////////////////////////////////////////////////////////////////////////
//! Returns the byte pointed to by ERDPT and increments ERDPT so MIOS32_ENC28J60_MACGet()
//! can be called again. The increment will follow the receive buffer wrapping boundary.
//!
//! EWRPT is incremented after the read.
//! \return < 0 on errors
//! \return >= 0: Byte read from the ENC28J60's RAM
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_MACGet(void)
{
  s32 status;

  CSN_0;
  status = MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, RBM);
  if( status >= 0 )
    status = MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, 0xff);
  CSN_1;

  return status;
}
Ejemplo n.º 4
0
/////////////////////////////////////////////////////////////////////////////
//! Sends the System Reset SPI command to the Ethernet controller.
//! It resets all register contents (except for ECOCON) and returns the 
//! device to the power on default state.
//!
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_SendSystemReset(void)
{
  s32 status = 0;
#if 0
  // sequence taken from SendSystemReset() of Microchip driver

  // Note: The power save feature may prevent the reset from executing, so 
  // we must make sure that the device is not in power save before issuing 
  // a reset.
  if( (status=MIOS32_ENC28J60_BFCReg(ECON2, ECON2_PWRSV)) < 0 )
    return status;

  // Give some opportunity for the regulator to reach normal regulation and 
  // have all clocks running
  MIOS32_DELAY_Wait_uS(1000); // 1 mS
#endif
  // Execute the System Reset command
  status = 0;
  CSN_0;
  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, SR);
  CSN_1;
  if( status < 0 )
    return status;

  // Wait for the oscillator start up timer and PHY to become ready
  MIOS32_DELAY_Wait_uS(1000); // 1 mS

  return 0; // no error
}
Ejemplo n.º 5
0
static void TASK_SPI_Handler(void *pvParameters)
{
  // fill Tx Buffer with housenumbers
  {
    int i;
    for(i=0; i<TRANSFER_BUFFER_SIZE; ++i)
      tx_buffer[i] = i;
  }

  while( 1 ) {
    int i;
    for(i=0; i<TRANSFER_BUFFER_SIZE; ++i) {
      // toggle Status LED to as a sign of live
      MIOS32_BOARD_LED_Set(1, ~MIOS32_BOARD_LED_Get());

      // receive byte
      rx_buffer[i] = MIOS32_SPI_TransferByte(SLAVE_SPI, tx_buffer[i]);
    }

    SPI_Callback();

    // print received bytes
    MIOS32_MIDI_SendDebugHexDump((u8 *)rx_buffer, TRANSFER_BUFFER_SIZE);
  }
}
Ejemplo n.º 6
0
/////////////////////////////////////////////////////////////////////////////
//! Sends the 8 bit RCR opcode/Address byte as well as a dummy byte over the 
//! SPI and then retrives the register contents in the last 8 SPI clocks.
//!
//! This routine cannot be used to access ETH or PHY registers.
//! Use MIOS32_ENC28J60_ReadETHReg() or MIOS32_ENC28J60_ReadPHYReg() for that
//! purpose.
//! \param[in] address 5 bit address of the MAC or MII register to read from.
//! \return < 0 on errors
//! \return >= 0: Byte read from the Ethernet controller's MAC/MII register.
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_ReadMACReg(u8 address)
{
  s32 status = 0;

  // send opcode
  CSN_0;
  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, RCR | address);
  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, 0xff); // dummy byte

  if( status >= 0 ) {
    // read register
    status = MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, 0xff);
  }

  CSN_1;

  return status;
}
Ejemplo n.º 7
0
/////////////////////////////////////////////////////////////////////////////
//! Sends the 8 bit RCR opcode/Address byte over the SPI and then retrives 
//! the register contents in the next 8 SPI clocks.
//!
//! This routine cannot be used to access MAC/MII or PHY registers.
//! Use MIOS32_ENC28J60_ReadMACReg() or MIOS32_ENC28J60_ReadPHYReg() for that
//! purpose.
//! \param[in] address 5 bit address of the ETH control register to read from.
//! \return < 0 on errors
//! \return >= 0: Byte read from the Ethernet controller's ETH register.
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_ReadETHReg(u8 address)
{
  s32 status = 0;

  // send opcode
  CSN_0;

  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, RCR | address);

  // skip if something already failed
  if( status >= 0 ) {
    // read register
    status = MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, 0xff);
  }
  CSN_1;

  return status;
}
Ejemplo n.º 8
0
/////////////////////////////////////////////////////////////////////////////
//! writes several sequential bytes to the ENC28J60 RAM. It performs faster 
//! than multiple MIOS32_ENC28J60_MACPut() calls.
//!
//! EWRPT is incremented by len.
//! \param[in] buffer source buffer
//! \param[in] len number of bytes which should be written
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_MACPutArray(u8 *buffer, u16 len)
{
  s32 status = 0;

  CSN_0;
  status |= MIOS32_SPI_TransferByte(MIOS32_ENC28J60_SPI, WBM);
  status |= MIOS32_SPI_TransferBlock(MIOS32_ENC28J60_SPI, buffer, NULL, len, NULL);
  CSN_1;

  return status;
}
Ejemplo n.º 9
0
/////////////////////////////////////////////////////////////////////////////
//! (Re-)initializes SPI peripheral transfer mode
//! By default, all SPI peripherals are configured with 
//! MIOS32_SPI_MODE_CLK1_PHASE1 and MIOS32_SPI_PRESCALER_128
//!
//! \param[in] spi SPI number (0, 1 or 2)
//! \param[in] spi_mode configures clock and capture phase:
//! <UL>
//!   <LI>MIOS32_SPI_MODE_CLK0_PHASE0: Idle level of clock is 0, data captured at rising edge
//!   <LI>MIOS32_SPI_MODE_CLK0_PHASE1: Idle level of clock is 0, data captured at falling edge
//!   <LI>MIOS32_SPI_MODE_CLK1_PHASE0: Idle level of clock is 1, data captured at falling edge
//!   <LI>MIOS32_SPI_MODE_CLK1_PHASE1: Idle level of clock is 1, data captured at rising edge
//! </UL>
//! \param[in] spi_prescaler configures the SPI speed:
//! <UL>
//!   <LI>MIOS32_SPI_PRESCALER_2: sets clock rate 27.7~ nS @ 72 MHz (36 MBit/s) (only supported for spi==0, spi1 uses 4 instead)
//!   <LI>MIOS32_SPI_PRESCALER_4: sets clock rate 55.5~ nS @ 72 MHz (18 MBit/s)
//!   <LI>MIOS32_SPI_PRESCALER_8: sets clock rate 111.1~ nS @ 72 MHz (9 MBit/s)
//!   <LI>MIOS32_SPI_PRESCALER_16: sets clock rate 222.2~ nS @ 72 MHz (4.5 MBit/s)
//!   <LI>MIOS32_SPI_PRESCALER_32: sets clock rate 444.4~ nS @ 72 MHz (2.25 MBit/s)
//!   <LI>MIOS32_SPI_PRESCALER_64: sets clock rate 888.8~ nS @ 72 MHz (1.125 MBit/s)
//!   <LI>MIOS32_SPI_PRESCALER_128: sets clock rate 1.7~ uS @ 72 MHz (0.562 MBit/s)
//!   <LI>MIOS32_SPI_PRESCALER_256: sets clock rate 3.5~ uS @ 72 MHz (0.281 MBit/s)
//! </UL>
//! \return 0 if no error
//! \return -1 if disabled SPI port selected
//! \return -2 if unsupported SPI port selected
//! \return -3 if invalid spi_prescaler selected
//! \return -4 if invalid spi_mode selected
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_SPI_TransferModeInit(u8 spi, mios32_spi_mode_t spi_mode, mios32_spi_prescaler_t spi_prescaler)
{
  // SPI configuration
  SPI_InitTypeDef SPI_InitStructure;
  SPI_InitStructure.SPI_Direction     = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode          = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize      = SPI_DataSize_8b;
  SPI_InitStructure.SPI_NSS           = SPI_NSS_Soft;
  SPI_InitStructure.SPI_FirstBit      = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;

  switch( spi_mode ) {
    case MIOS32_SPI_MODE_SLAVE_CLK0_PHASE0:
      SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
      SPI_InitStructure.SPI_NSS  = SPI_NSS_Hard;
    case MIOS32_SPI_MODE_CLK0_PHASE0:
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
      break;

    case MIOS32_SPI_MODE_SLAVE_CLK0_PHASE1:
      SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
      SPI_InitStructure.SPI_NSS  = SPI_NSS_Hard;
    case MIOS32_SPI_MODE_CLK0_PHASE1:
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
      break;

    case MIOS32_SPI_MODE_SLAVE_CLK1_PHASE0:
      SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
      SPI_InitStructure.SPI_NSS  = SPI_NSS_Hard;
    case MIOS32_SPI_MODE_CLK1_PHASE0:
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
      break;

    case MIOS32_SPI_MODE_SLAVE_CLK1_PHASE1:
      SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
      SPI_InitStructure.SPI_NSS  = SPI_NSS_Hard;
    case MIOS32_SPI_MODE_CLK1_PHASE1:
      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
      break;
    default:
      return -4; // invalid SPI clock/phase mode
  }

  if( spi_prescaler >= 8 )
    return -3; // invalid prescaler selected

  switch( spi ) {
    case 0: {
#ifdef MIOS32_DONT_USE_SPI0
      return -1; // disabled SPI port
#else
      u16 prev_cr1 = MIOS32_SPI0_PTR->CR1;
      // SPI1 perpipheral is located in APB2 domain and clocked at full speed
      // therefore we have to add +1 to the prescaler
      SPI_InitStructure.SPI_BaudRatePrescaler = ((u16)spi_prescaler&7) << 3;
      SPI_Init(MIOS32_SPI0_PTR, &SPI_InitStructure);

      if( SPI_InitStructure.SPI_Mode == SPI_Mode_Master ) {
	if( (prev_cr1 ^ MIOS32_SPI0_PTR->CR1) & 3 ) { // CPOL and CPHA located at bit #1 and #0
	  // clock configuration has been changed - we should send a dummy byte
	  // before the application activates chip select.
	  // this solves a dependency between SDCard and ENC28J60 driver
	  MIOS32_SPI_TransferByte(spi, 0xff);
	}
      }
#endif
    } break;

    case 1: {
#ifdef MIOS32_DONT_USE_SPI1
      return -1; // disabled SPI port
#else
      u16 prev_cr1 = MIOS32_SPI1_PTR->CR1;

      // SPI2 perpipheral is located in APB1 domain and clocked at half speed
      if( spi_prescaler == 0 )
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
      else
	SPI_InitStructure.SPI_BaudRatePrescaler = (((u16)spi_prescaler&7)-1) << 3;
      SPI_Init(MIOS32_SPI1_PTR, &SPI_InitStructure);

      if( SPI_InitStructure.SPI_Mode == SPI_Mode_Master ) {
	if( (prev_cr1 ^ MIOS32_SPI1_PTR->CR1) & 3 ) { // CPOL and CPHA located at bit #1 and #0
	  // clock configuration has been changed - we should send a dummy byte
	  // before the application activates chip select.
	  // this solves a dependency between SDCard and ENC28J60 driver
	  MIOS32_SPI_TransferByte(spi, 0xff);
	}
      }
#endif
    } break;

    case 2:
#ifdef MIOS32_DONT_USE_SPI2
      return -1; // disabled SPI port
#else
      if( SPI_InitStructure.SPI_Mode == SPI_Mode_Slave ) {
	return -3; // slave mode not supported for this SPI
      }

      // no clock prescaler for SW emulated SPI
      // remember mode settings
      sw_spi2_mode = spi_mode;

      // set clock idle level
      switch( sw_spi2_mode ) {
        case MIOS32_SPI_MODE_CLK0_PHASE0:
        case MIOS32_SPI_MODE_CLK0_PHASE1:
	  MIOS32_SPI2_SET_SCLK_0;
	  break;
        case MIOS32_SPI_MODE_CLK1_PHASE0:
        case MIOS32_SPI_MODE_CLK1_PHASE1:
	  MIOS32_SPI2_SET_SCLK_1;
	  break;
        default:
	  return -4; // invalid SPI clock/phase mode
      }

      break;
#endif

    default:
      return -2; // unsupported SPI port
  }

  return 0; // no error
}
Ejemplo n.º 10
0
/////////////////////////////////////////////////////////////////////////////
//! Transfers a block of bytes via DMA.
//! \param[in] spi SPI number (0, 1 or 2)
//! \param[in] send_buffer pointer to buffer which should be sent.<BR>
//! If NULL, 0xff (all-one) will be sent.
//! \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
//! If NULL, received bytes will be discarded.
//! \param[in] len number of bytes which should be transfered
//! \param[in] callback pointer to callback function which will be executed
//! from DMA channel interrupt once the transfer is finished.
//! If NULL, no callback function will be used, and MIOS32_SPI_TransferBlock() will
//! block until the transfer is finished.
//! \return >= 0 if no error during transfer
//! \return -1 if disabled SPI port selected
//! \return -2 if unsupported SPI port selected
//! \return -3 if function has been called during an ongoing DMA transfer
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_SPI_TransferBlock(u8 spi, u8 *send_buffer, u8 *receive_buffer, u16 len, void *callback)
{
  SPI_TypeDef *spi_ptr;
  DMA_Channel_TypeDef *dma_tx_ptr, *dma_rx_ptr;

  switch( spi ) {
    case 0:
#ifdef MIOS32_DONT_USE_SPI0
      return -1; // disabled SPI port
#else
      spi_ptr = MIOS32_SPI0_PTR;
      dma_tx_ptr = MIOS32_SPI0_DMA_TX_PTR;
      dma_rx_ptr = MIOS32_SPI0_DMA_RX_PTR;
      break;
#endif

    case 1:
#ifdef MIOS32_DONT_USE_SPI1
      return -1; // disabled SPI port
#else
      spi_ptr = MIOS32_SPI1_PTR;
      dma_tx_ptr = MIOS32_SPI1_DMA_TX_PTR;
      dma_rx_ptr = MIOS32_SPI1_DMA_RX_PTR;
      break;
#endif

    case 2:
#ifdef MIOS32_DONT_USE_SPI2
      return -1; // disabled SPI port
#else
    // Software Emulation
    {
      u32 pos;

      // we have 4 cases:
      if( receive_buffer != NULL ) {
	if( send_buffer != NULL ) {
	  for(pos=0; pos<len; ++pos)
	    *receive_buffer++ = MIOS32_SPI_TransferByte(spi, *send_buffer++);
	} else {
	  for(pos=0; pos<len; ++pos)
	    *receive_buffer++ = MIOS32_SPI_TransferByte(spi, 0xff);
	}
      } else {
	// TODO: we could use an optimized "send only" function to speed up the SW emulation!
	if( send_buffer != NULL ) {
	  for(pos=0; pos<len; ++pos)
	    MIOS32_SPI_TransferByte(spi, *send_buffer++);
	} else {
	  // nothing to do...
	}
      }

      // set callback function
      spi_callback[spi] = callback;
      if( spi_callback[spi] != NULL )
	spi_callback[spi]();

      return 0; // END of SW emulation - EXIT here!
    } break;
#endif

    default:
      return -2; // unsupported SPI port
  }

  // exit if ongoing transfer
  if( dma_rx_ptr->CNDTR )
    return -3;

  // set callback function
  spi_callback[spi] = callback;

  // ensure that previously received value doesn't cause DMA access
  if( spi_ptr->DR );

  // configure Rx channel
  // TK: optimization method: read rx_CCR once, write back only when required
  // the channel must be disabled to configure new values
  u32 rx_CCR = dma_rx_ptr->CCR & ~CCR_ENABLE;
  dma_rx_ptr->CCR = rx_CCR;
  if( receive_buffer != NULL ) {
    // enable memory addr. increment - bytes written into receive buffer
    dma_rx_ptr->CMAR = (u32)receive_buffer;
    rx_CCR |= DMA_MemoryInc_Enable;
  } else {
    // disable memory addr. increment - bytes written into dummy buffer
    rx_dummy_byte = 0xff;
    dma_rx_ptr->CMAR = (u32)&rx_dummy_byte;
    rx_CCR &= ~DMA_MemoryInc_Enable;
  }
  dma_rx_ptr->CNDTR = len;
  rx_CCR |= CCR_ENABLE;


  // configure Tx channel
  // TK: optimization method: read tx_CCR once, write back only when required
  // the channel must be disabled to configure new values
  u32 tx_CCR = dma_tx_ptr->CCR & ~CCR_ENABLE;
  dma_tx_ptr->CCR = tx_CCR;
  if( send_buffer != NULL ) {
    // enable memory addr. increment - bytes read from send buffer
    dma_tx_ptr->CMAR = (u32)send_buffer;
    tx_CCR |= DMA_MemoryInc_Enable;
  } else {
    // disable memory addr. increment - bytes read from dummy buffer
    tx_dummy_byte = 0xff;
    dma_tx_ptr->CMAR = (u32)&tx_dummy_byte;
    tx_CCR &= ~DMA_MemoryInc_Enable;
  }
  dma_tx_ptr->CNDTR = len;

  // enable DMA interrupt if callback function active
  if( callback != NULL ) {
    rx_CCR |= DMA_IT_TC;
    dma_rx_ptr->CCR = rx_CCR;

    // start DMA transfer
    dma_tx_ptr->CCR = tx_CCR | CCR_ENABLE;
  } else {
    rx_CCR &= ~DMA_IT_TC;
    dma_rx_ptr->CCR = rx_CCR;

    // start DMA transfer
    dma_tx_ptr->CCR = tx_CCR | CCR_ENABLE;

    // if no callback: wait until all bytes have been transmitted/received
    while( dma_rx_ptr->CNDTR );
  }

  return 0; // no error;
}