Example #1
0
/////////////////////////////////////////////////////////////////////////////
//! Checks if the chip is still connected by reading the revision ID.<BR>
//! This takes ca. 2 uS
//!
//! If the ID value is within the range of 0x01..0x1f, MIOS32_ENC28J60_PowerOn()
//! will be called by this function to initialize the device completely.
//!
//! Example for Connection/Disconnection detection:
//! \code
//! // this function is called each second from a low-priority task
//! // If multiple tasks are accessing the ENC28J60 chip, add a semaphore/mutex
//! //  to avoid IO access collisions with other tasks!
//! u8 enc28j60_available;
//! s32 ETHERNET_CheckENC28J60(void)
//! {
//!   // check if ENC28J60 is connected
//!   u8 prev_enc28j60_available = enc28j60_available;
//!   enc28j60_available = MIOS32_ENC28J60_CheckAvailable(prev_enc28j60_available);
//! 
//!   if( enc28j60_available && !prev_enc28j60_available ) {
//!     // ENC28J60 has been connected
//! 
//!     // now it's possible to receive/send packages
//! 
//!   } else if( !enc28j60_available && prev_enc28j60_available ) {
//!     // ENC28J60 has been disconnected
//! 
//!     // here you can notify your application about this state
//!   }
//! 
//!   return 0; // no error
//! }
//! \endcode
//! \param[in] was_available should only be set if the ENC28J60 was previously available
//! \return 0 if no response from ENC28J60
//! \return 1 if ENC28J60 is accessible
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_CheckAvailable(u8 was_available)
{
  s32 status = 0;
  MIOS32_ENC28J60_MUTEX_TAKE;
  if( (status=MIOS32_SPI_TransferModeInit(MIOS32_ENC28J60_SPI, MIOS32_SPI_MODE_CLK0_PHASE0, MIOS32_SPI_PRESCALER_4)) < 0 ) 
	goto error;
  
  // read revision ID to check if ENC28J60 is connected
  MIOS32_ENC28J60_BankSel(EREVID);
  if( (status=MIOS32_ENC28J60_ReadMACReg((u8)EREVID)) < 0 ) 
	goto error;

  // chip not connected if value < 1 or >= 32
  if( !status || status >= 32 ) 
	goto error;

	// initialize chip if it has been detected
  if( !was_available ) {
    // run power-on sequence
    if( MIOS32_ENC28J60_PowerOn() < 0 )
 	  goto error;

  }
  
  MIOS32_ENC28J60_MUTEX_GIVE;
  return 1; // ENC28J60 available
error:
  MIOS32_ENC28J60_MUTEX_GIVE;
  return 0; // ENC28J60 not available.
}
Example #2
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called after startup to initialize the application
/////////////////////////////////////////////////////////////////////////////
void APP_Init(void)
{
  // create semaphores
  xMIDIINSemaphore = xSemaphoreCreateRecursiveMutex();
  xMIDIOUTSemaphore = xSemaphoreCreateRecursiveMutex();

  // install SysEx callback
  MIOS32_MIDI_SysExCallback_Init(APP_SYSEX_Parser);

  // install MIDI Rx/Tx callback functions
  MIOS32_MIDI_DirectRxCallback_Init(&NOTIFY_MIDI_Rx);
  MIOS32_MIDI_DirectTxCallback_Init(&NOTIFY_MIDI_Tx);

  // install timeout callback function
  MIOS32_MIDI_TimeOutCallback_Init(&NOTIFY_MIDI_TimeOut);

  // limit the number of DIN/DOUT SRs which will be scanned for faster scan rate
  MIOS32_SRIO_ScanNumSet(2);

  // init keyboard functions
  KEYBOARD_Init(0);

  // read EEPROM content
  PRESETS_Init(0);

  // init MIDI port/router handling
  MIDI_PORT_Init(0);
  MIDI_ROUTER_Init(0);

  // init terminal
  TERMINAL_Init(0);

  // init MIDImon
  MIDIMON_Init(0);

  // start uIP task
  UIP_TASK_Init(0);

  // print welcome message on MIOS terminal
  MIOS32_MIDI_SendDebugMessage("\n");
  MIOS32_MIDI_SendDebugMessage("=================\n");
  MIOS32_MIDI_SendDebugMessage("%s\n", MIOS32_LCD_BOOT_MSG_LINE1);
  MIOS32_MIDI_SendDebugMessage("=================\n");
  MIOS32_MIDI_SendDebugMessage("\n");

  // speed up SPI transfer rate (was MIOS32_SPI_PRESCALER_128, initialized by MIOS32_SRIO_Init())
  MIOS32_SPI_TransferModeInit(MIOS32_SRIO_SPI, MIOS32_SPI_MODE_CLK1_PHASE1, MIOS32_SPI_PRESCALER_128);
  // prescaler 64 results into a transfer rate of 0.64 uS per bit
  // when 2 SRs are transfered, we are able to scan the whole 16x8 matrix in 300 uS

  // standard SRIO scan has been disabled in programming_models/traditional/main.c via MIOS32_DONT_SERVICE_SRIO_SCAN in mios32_config.h
  // start the scan here - and retrigger it whenever it's finished
  APP_SRIO_ServicePrepare();
  MIOS32_SRIO_ScanStart(APP_SRIO_ServiceFinish);

  // start tasks
  xTaskCreate(TASK_Period_1mS, (signed portCHAR *)"1mS", configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_PERIOD_1mS, NULL);
}
Example #3
0
/////////////////////////////////////////////////////////////////////////////
// This hook is called after startup to initialize the application
/////////////////////////////////////////////////////////////////////////////
void APP_Init(void)
{
  // initialize all LEDs
  MIOS32_BOARD_LED_Init(0xffffffff);


  // initialize SPI interface
  // ensure that fast pin drivers are activated
  MIOS32_SPI_IO_Init(SLAVE_SPI, MIOS32_SPI_PIN_SLAVE_DRIVER_STRONG);

  // init SPI port
  MIOS32_SPI_TransferModeInit(SLAVE_SPI, MIOS32_SPI_MODE_SLAVE_CLK1_PHASE1, MIOS32_SPI_PRESCALER_128);

  // start task
  xTaskCreate(TASK_SPI_Handler, (signed portCHAR *)"SPI_Handler", configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_SPI_HANDLER, NULL);
}
Example #4
0
/////////////////////////////////////////////////////////////////////////////
//! Receives a package from ENC28J60 chip
//! param[in] buffer Pointer to buffer which gets the playload
//! param[in] buffer_size Max. number of bytes which can be received
//! \return < 0 on errors
//! \return -16 if inconsistencies have been detected, and the ENC28J60 device has been reseted
//! \return 0 if no package has been received
//! \return > 0 number of received bytes
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_PackageReceive(u8 *buffer, u16 buffer_size)
{
  s32 status = 0;
  s32 package_count;
  u16 packet_len = 0;

  MIOS32_ENC28J60_MUTEX_TAKE;

  // re-init SPI port for fast frequency access (ca. 18 MBit/s)
  // this is required for the case that the SPI port is shared with other devices
  if( (status=MIOS32_SPI_TransferModeInit(MIOS32_ENC28J60_SPI, MIOS32_SPI_MODE_CLK0_PHASE0, MIOS32_SPI_PRESCALER_4)) < 0 ) 
    goto error;
	
  // Test if at least one packet has been received and is waiting
  status |= MIOS32_ENC28J60_BankSel(EPKTCNT);
  package_count = MIOS32_ENC28J60_ReadETHReg((u8)EPKTCNT);
  status |= MIOS32_ENC28J60_BankSel(ERDPTL);

  if( status < 0 ) 
    goto error;
	
  if( package_count <= 0 ) {
    status=package_count;
    goto error;
  }
  // Make absolutely certain that any previous packet was discarded
  if( !WasDiscarded ) {
    status = MIOS32_ENC28J60_MACDiscardRx();
    status = (status < 0) ? status : 0;
    goto error;
  }

  // Set the SPI read pointer to the beginning of the next unprocessed packet
  u16 CurrentPacketLocation = NextPacketLocation;
  status |= MIOS32_ENC28J60_WriteReg(ERDPTL, CurrentPacketLocation & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ERDPTH, (CurrentPacketLocation >> 8) & 0xff);

  if( status < 0 )
    goto error;
  
  
  // Obtain the MAC header from the Ethernet buffer
  ENC_PREAMBLE header;
  status |= MIOS32_ENC28J60_MACGetArray((u8 *)&header, sizeof(header));

  // Validate the data returned from the ENC28J60.  Random data corruption, 
  // such as if a single SPI bit error occurs while communicating or a 
  // momentary power glitch could cause this to occur in rare circumstances.
  if( header.NextPacketPointer > RXSTOP ||
      (header.NextPacketPointer & 1) ||
      header.StatusVector.bits.Zero ||
      header.StatusVector.bits.ByteCount > MIOS32_ENC28J60_MAX_FRAME_SIZE ) {

    MIOS32_MIDI_SendDebugMessage("[MIOS32_ENC28J60_PackageReceive] glitch detected - Ptr: %04x, Status: %04x (max: %04x) %02x%02x\n",
				 header.NextPacketPointer,
				 header.StatusVector.bits.ByteCount,
				 MIOS32_ENC28J60_MAX_FRAME_SIZE,
				 header.StatusVector.v[3], header.StatusVector.v[2]);
    // Reset device (must keep mutex)
    MIOS32_ENC28J60_PowerOn();
    // no packet received
    status=-16;
    goto error;
  }

  // Save the location where the hardware will write the next packet to
  NextPacketLocation = header.NextPacketPointer;

  // Mark this packet as discardable
  WasDiscarded = 0;

  // empty package or CRC/symbol errors?
  packet_len = header.StatusVector.bits.ByteCount;
  if( !packet_len || header.StatusVector.bits.CRCError || !header.StatusVector.bits.ReceiveOk ) {
    status = MIOS32_ENC28J60_MACDiscardRx(); // discard package immediately
    status = (status < 0) ? status : 0;
    goto error;
  }

  // ensure that we don't read more bytes than the buffer can store
  if( packet_len > buffer_size )
    packet_len = buffer_size;

  // read bytes into buffer
  status = MIOS32_ENC28J60_MACGetArray(buffer, packet_len);

  // discard package immediately
  status |= MIOS32_ENC28J60_MACDiscardRx();
  
  // No more processing so can safely give mutex back.
error:
  MIOS32_ENC28J60_MUTEX_GIVE;

  if( status < 0 )
    return status;

  return packet_len; // no error: return packet length
}
Example #5
0
/////////////////////////////////////////////////////////////////////////////
//! Changes the MAC address.
//!
//! Usually called by MIOS32_ENC28J60_PowerOn(), but could also be used
//! during runtime.
//!
//! The default MAC address is predefined by MIOS32_ENC28J60_MY_MAC_ADDR[123456]
//! and can be overruled in mios32_config.h if desired.
//!
//! \param[in] new_mac_addr an array with 6 bytes which define the MAC
//! address. If all bytes are 0 (default), the serial number of STM32 will be
//! taken instead, which should be unique in your private network.
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_MAC_AddrSet(u8 new_mac_addr[6])
{
  s32 status;

  // re-init SPI port for fast frequency access (ca. 18 MBit/s)
  // this is required for the case that the SPI port is shared with other devices
  if( (status=MIOS32_SPI_TransferModeInit(MIOS32_ENC28J60_SPI, MIOS32_SPI_MODE_CLK0_PHASE0, MIOS32_SPI_PRESCALER_4)) < 0 )
    return status;

  // check for all-zero
  int i;
  int ored = 0;
  for(i=0; i<6; ++i)
    ored |= new_mac_addr[i];

  if( ored ) {
    // MAC address != 0 -> take over new address
    memcpy(mac_addr, new_mac_addr, 6);
  } else {
    // get serial number
    char serial[32];
    MIOS32_SYS_SerialNumberGet(serial);
    int len = strlen(serial);
    if( len < 12 ) {
      // no serial number or not large enough - we should at least set the MAC address to != 0
      for(i=0; i<6; ++i)
	mac_addr[i] = i;
    } else {
#if 0     
      for(i=0; i<6; ++i) {
	// convert hex string to dec
	char digitl = serial[len-i*2 - 1];
	char digith = serial[len-i*2 - 2];
	mac_addr[i] = ((digitl >= 'A') ? (digitl-'A'+10) : (digitl-'0')) |
	  (((digith >= 'A') ? (digith-'A'+10) : (digith-'0')) << 4);
#else
      // TK: for some reasons, my Fritzbox router doesn't accept MACs that are not starting with 0x00
      mac_addr[0] = 0x00;
      for(i=1; i<6; ++i) {
	// convert hex string to dec
	char digitl = serial[len-(i-1)*2 - 1];
	char digith = serial[len-(i-1)*2 - 2];
	mac_addr[i] = ((digitl >= 'A') ? (digitl-'A'+10) : (digitl-'0')) |
	  (((digith >= 'A') ? (digith-'A'+10) : (digith-'0')) << 4);
#endif
      }
    }
  }

  status |= MIOS32_ENC28J60_BankSel(MAADR1);
  status |= MIOS32_ENC28J60_WriteReg((u8)MAADR1, mac_addr[0]);
  status |= MIOS32_ENC28J60_WriteReg((u8)MAADR2, mac_addr[1]);
  status |= MIOS32_ENC28J60_WriteReg((u8)MAADR3, mac_addr[2]);
  status |= MIOS32_ENC28J60_WriteReg((u8)MAADR4, mac_addr[3]);
  status |= MIOS32_ENC28J60_WriteReg((u8)MAADR5, mac_addr[4]);
  status |= MIOS32_ENC28J60_WriteReg((u8)MAADR6, mac_addr[5]);

  return status;
}


/////////////////////////////////////////////////////////////////////////////
//! Returns the current MAC address
//! \return u8 pointer with 6 bytes
/////////////////////////////////////////////////////////////////////////////
u8 *MIOS32_ENC28J60_MAC_AddrGet(void)
{
  return mac_addr;
}


/////////////////////////////////////////////////////////////////////////////
//! Sends a package to the ENC28J60 chip
//! param[in] buffer Pointer to buffer which contains the playload
//! param[in] len number of bytes which should be sent
//! param[in] buffer2 Pointer to optional second buffer which contains additional playload
//!           (can be NULL if no additional data)
//! param[in] len2 number of bytes in second buffer
//!           (should be 0 if no additional data)
//! \return < 0 on errors
//! \return -16 if previous package hasn't been sent yet (this is checked 
//!             1000 times before the function exits)
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_PackageSend(u8 *buffer, u16 len, u8 *buffer2, u16 len2)
{
  s32 status = 0;

  MIOS32_ENC28J60_MUTEX_TAKE;

  // re-init SPI port for fast frequency access (ca. 18 MBit/s)
  // this is required for the case that the SPI port is shared with other devices
  if( (status=MIOS32_SPI_TransferModeInit(MIOS32_ENC28J60_SPI, MIOS32_SPI_MODE_CLK0_PHASE0, MIOS32_SPI_PRESCALER_4)) < 0 ) 
    goto error;
	
  // wait until a new package can be transmitted
  int timeout_ctr = 1000;
  while( --timeout_ctr > 0 ) {
    status = MIOS32_ENC28J60_ReadETHReg(ECON1);
    if( status < 0 ) 
      goto error;
    if( !(status & ECON1_TXRTS) )
      break;
  }

  if( timeout_ctr == 0 ) {
    status=-16;
    goto error;
  }
  // Set the SPI write pointer to the beginning of the transmit buffer
  status |= MIOS32_ENC28J60_BankSel(EWRPTL);
  status |= MIOS32_ENC28J60_WriteReg(EWRPTL, TXSTART & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(EWRPTH, (TXSTART >> 8) & 0xff);

  if( status < 0 ) 
    goto error;
  
  // Calculate where to put the TXND pointer
  u16 end_addr = TXSTART + len + len2; // package control byte has already been considered in this calculation (+1 .. -1)

  // Write the TXND pointer into the registers, given the dataLen given
  status |= MIOS32_ENC28J60_WriteReg(ETXNDL, end_addr & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ETXNDH, (end_addr >> 8) & 0xff);

  if( status < 0 ) 
    goto error;
  
  // per-packet control byte:
  status |= MIOS32_ENC28J60_MACPut(0x07); // enable CRC calculation and padding to 60 bytes

  // send buffer
  status |= MIOS32_ENC28J60_MACPutArray(buffer, len);

  // send second buffer if available
  if( buffer2 != NULL && len2 ) {
    status |= MIOS32_ENC28J60_MACPutArray(buffer2, len2);
  }

  // Reset transmit logic if a TX Error has previously occured
  // This is a silicon errata workaround
  status |= MIOS32_ENC28J60_BFSReg(ECON1, ECON1_TXRST);
  status |= MIOS32_ENC28J60_BFCReg(ECON1, ECON1_TXRST);
  status |= MIOS32_ENC28J60_BFCReg(EIR, EIR_TXERIF | EIR_TXIF);

  // Start the transmission
  status |= MIOS32_ENC28J60_BFSReg(ECON1, ECON1_TXRTS);

  // This one is a bit pointless but we may add special rev code below!
  if( status < 0 ) 
    goto error;
	
  // Revision B5 and B7 silicon errata workaround
  if( rev_id == 0x05 || rev_id == 0x06 ) {
    // TODO --- add a lot of code here
  }

error:
  // We have finished with the mutex.
  MIOS32_ENC28J60_MUTEX_GIVE;
	
  return status;
}
Example #6
0
/////////////////////////////////////////////////////////////////////////////
//! Connects to ENC28J60 chip
//! \return < 0 if initialisation sequence failed
//! \return -16 if clock not ready after system reset
//! \return -17 if unsupported revision ID
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC28J60_PowerOn(void)
{
  s32 status;

  
  // deactivate chip select
  CSN_1;

  // ensure that fast pin drivers are activated
  MIOS32_SPI_IO_Init(MIOS32_ENC28J60_SPI, MIOS32_SPI_PIN_DRIVER_STRONG);

  // init SPI port for fast frequency access (ca. 18 MBit/s)
  if( (status=MIOS32_SPI_TransferModeInit(MIOS32_ENC28J60_SPI, MIOS32_SPI_MODE_CLK0_PHASE0, MIOS32_SPI_PRESCALER_4)) < 0 ) 
    return status;
  
  // send system reset command

  // RESET the entire ENC28J60, clearing all registers
  // Also wait for CLKRDY to become set.
  // Bit 3 in ESTAT is an unimplemented bit.  If it reads out as '1' that
  // means the part is in RESET or there is something wrong with the SPI 
  // connection.  This routine makes sure that we can communicate with the 
  // ENC28J60 before proceeding.
  if( (status=MIOS32_ENC28J60_SendSystemReset()) < 0 )
    return status;

  // check if chip is accessible (it should after ca. 1 mS)
  if( (status=MIOS32_ENC28J60_ReadETHReg(ESTAT)) < 0 )
    return status;

  if( (status & 0x08) || !(status & ESTAT_CLKRDY) )
    return -16; // no access to chip

  // read and check revision ID, this gives us another check if device is available
  MIOS32_ENC28J60_BankSel(EREVID);
  if( (status=MIOS32_ENC28J60_ReadMACReg((u8)EREVID)) < 0 )
    return status;

  rev_id = status;

  if( !rev_id || rev_id >= 32 ) {
    return -17; // unsupported revision ID
  }

  // Start up in Bank 0 and configure the receive buffer boundary pointers 
  // and the buffer write protect pointer (receive buffer read pointer)
  WasDiscarded = 1;
  NextPacketLocation = RXSTART;

  MIOS32_ENC28J60_BankSel(ERXSTL);
  status |= MIOS32_ENC28J60_WriteReg(ERXSTL,   (RXSTART) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ERXSTH,   ((RXSTART) >> 8) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ERXRDPTL, (RXSTOP) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ERXRDPTH, ((RXSTOP) >> 8) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ERXNDL,   (RXSTOP) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ERXNDH,   ((RXSTOP) >> 8) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ETXSTL,   (TXSTART) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(ETXSTH,   ((TXSTART) >> 8) & 0xff);

  // Write a permanant per packet control byte of 0x00
  status |= MIOS32_ENC28J60_WriteReg(EWRPTL,   (TXSTART) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg(EWRPTH,   ((TXSTART) >> 8) & 0xff);
  status |= MIOS32_ENC28J60_MACPut(0x00);

  // Enter Bank 1 and configure Receive Filters 
  // (No need to reconfigure - Unicast OR Broadcast with CRC checking is 
  // acceptable)
  // Write ERXFCON_CRCEN only to ERXFCON to enter promiscuous mode

  // Promiscious mode example:
  // status |= MIOS32_ENC28J60_BankSel(ERXFCON);
  // status |= MIOS32_ENC28J60_WriteReg((u8)ERXFCON, ERXFCON_CRCEN);
        
  // Enter Bank 2 and configure the MAC
  status |= MIOS32_ENC28J60_BankSel(MACON1);

  // Enable the receive portion of the MAC
  status |= MIOS32_ENC28J60_WriteReg((u8)MACON1, MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN);
        
  // Pad packets to 60 bytes, add CRC, and check Type/Length field.
#if MIOS32_ENC28J60_FULL_DUPLEX
  status |= MIOS32_ENC28J60_WriteReg((u8)MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
  status |= MIOS32_ENC28J60_WriteReg((u8)MABBIPG, 0x15);  
#else
  status |= MIOS32_ENC28J60_WriteReg((u8)MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
  status |= MIOS32_ENC28J60_WriteReg((u8)MABBIPG, 0x12);  
#endif

  // Allow infinite deferals if the medium is continuously busy 
  // (do not time out a transmission if the half duplex medium is 
  // completely saturated with other people's data)
  status |= MIOS32_ENC28J60_WriteReg((u8)MACON4, MACON4_DEFER);

  // Late collisions occur beyond 63+8 bytes (8 bytes for preamble/start of frame delimiter)
  // 55 is all that is needed for IEEE 802.3, but ENC28J60 B5 errata for improper link pulse 
  // collisions will occur less often with a larger number.
  status |= MIOS32_ENC28J60_WriteReg((u8)MACLCON2, 63);
        
  // Set non-back-to-back inter-packet gap to 9.6us.  The back-to-back 
  // inter-packet gap (MABBIPG) is set by MACSetDuplex() which is called 
  // later.
  status |= MIOS32_ENC28J60_WriteReg((u8)MAIPGL, 0x12);
  status |= MIOS32_ENC28J60_WriteReg((u8)MAIPGH, 0x0C);

  // Set the maximum packet size which the controller will accept
  status |= MIOS32_ENC28J60_WriteReg((u8)MAMXFLL, (MIOS32_ENC28J60_MAX_FRAME_SIZE) & 0xff);
  status |= MIOS32_ENC28J60_WriteReg((u8)MAMXFLH, ((MIOS32_ENC28J60_MAX_FRAME_SIZE) >> 8) & 0xff);
        
  // initialize physical MAC address registers
  status |= MIOS32_ENC28J60_MAC_AddrSet(mac_addr);

  // Enter Bank 3 and Disable the CLKOUT output to reduce EMI generation
  status |= MIOS32_ENC28J60_BankSel(ECOCON);
  status |= MIOS32_ENC28J60_WriteReg((u8)ECOCON, 0x00);   // Output off (0V)
  //status |= MIOS32_ENC28J60_WriteReg((u8)ECOCON, 0x01); // 25.000MHz
  //status |= MIOS32_ENC28J60_WriteReg((u8)ECOCON, 0x03); // 8.3333MHz (*4 with PLL is 33.3333MHz)

  // Disable half duplex loopback in PHY.  Bank bits changed to Bank 2 as a 
  // side effect.
  status |= MIOS32_ENC28J60_WritePHYReg(PHCON2, PHCON2_HDLDIS);

  // Configure LEDA to display LINK status, LEDB to display TX/RX activity
  status |= MIOS32_ENC28J60_WritePHYReg(PHLCON, 0x3472);

  // Set the MAC and PHY into the proper duplex state
#if MIOS32_ENC28J60_FULL_DUPLEX
  status |= MIOS32_ENC28J60_WritePHYReg(PHCON1, PHCON1_PDPXMD);
#else
  status |= MIOS32_ENC28J60_WritePHYReg(PHCON1, 0x0000);
#endif
  status |= MIOS32_ENC28J60_BankSel(ERDPTL);                // Return to default Bank 0

  // Enable packet reception
  status |= MIOS32_ENC28J60_BFSReg(ECON1, ECON1_RXEN);

  return (status < 0) ? status : 0;
}
/////////////////////////////////////////////////////////////////////////////
//! Initializes SPI pins
//! \param[in] mode currently only mode 0 supported
//! \return < 0 if initialisation failed
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_SPI_Init(u32 mode)
{
  // currently only mode 0 supported
  if( mode != 0 )
    return -1; // unsupported mode

  DMA_InitTypeDef DMA_InitStructure;
  DMA_StructInit(&DMA_InitStructure);

  ///////////////////////////////////////////////////////////////////////////
  // SPI0
  ///////////////////////////////////////////////////////////////////////////
#ifndef MIOS32_DONT_USE_SPI0

  // disable callback function
  spi_callback[0] = NULL;

  // set RC pin(s) to 1
  MIOS32_SPI_RC_PinSet(0, 0, 1); // spi, rc_pin, pin_value
  MIOS32_SPI_RC_PinSet(0, 1, 1); // spi, rc_pin, pin_value

  // IO configuration
  MIOS32_SPI_IO_Init(0, MIOS32_SPI_PIN_DRIVER_WEAK_OD);

  // enable SPI peripheral clock (APB2 == high speed)
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

  // enable DMA1 clock
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  // DMA Configuration for SPI Rx Event
  DMA_Cmd(MIOS32_SPI0_DMA_RX_PTR, DISABLE);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&MIOS32_SPI0_PTR->DR;
  DMA_InitStructure.DMA_MemoryBaseAddr = 0; // will be configured later
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 0; // will be configured later
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(MIOS32_SPI0_DMA_RX_PTR, &DMA_InitStructure);

  // DMA Configuration for SPI Tx Event
  // (partly re-using previous DMA setup)
  DMA_Cmd(MIOS32_SPI0_DMA_TX_PTR, DISABLE);
  DMA_InitStructure.DMA_MemoryBaseAddr = 0; // will be configured later
  DMA_InitStructure.DMA_BufferSize = 0; // will be configured later
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_Init(MIOS32_SPI0_DMA_TX_PTR, &DMA_InitStructure);

  // enable SPI
  SPI_Cmd(MIOS32_SPI0_PTR, ENABLE);

  // enable SPI interrupts to DMA
  SPI_I2S_DMACmd(MIOS32_SPI0_PTR, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);

  // Configure DMA interrupt
  MIOS32_IRQ_Install(MIOS32_SPI0_DMA_IRQ_CHANNEL, MIOS32_IRQ_SPI_DMA_PRIORITY);

  // initial SPI peripheral configuration
  MIOS32_SPI_TransferModeInit(0, MIOS32_SPI_MODE_CLK1_PHASE1, MIOS32_SPI_PRESCALER_128);
#endif /* MIOS32_DONT_USE_SPI0 */


  ///////////////////////////////////////////////////////////////////////////
  // SPI1
  ///////////////////////////////////////////////////////////////////////////
#ifndef MIOS32_DONT_USE_SPI1

  // disable callback function
  spi_callback[1] = NULL;

  // set RC pin(s) to 1
  MIOS32_SPI_RC_PinSet(1, 0, 1); // spi, rc_pin, pin_value
  MIOS32_SPI_RC_PinSet(1, 1, 1); // spi, rc_pin, pin_value

  // IO configuration
  MIOS32_SPI_IO_Init(1, MIOS32_SPI_PIN_DRIVER_WEAK_OD);

  // enable SPI peripheral clock (APB1 == slow speed)
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

  // enable DMA1 clock
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  // DMA Configuration for SPI Rx Event
  DMA_Cmd(MIOS32_SPI1_DMA_RX_PTR, DISABLE);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&MIOS32_SPI1_PTR->DR;
  DMA_InitStructure.DMA_MemoryBaseAddr = 0; // will be configured later
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 0; // will be configured later
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(MIOS32_SPI1_DMA_RX_PTR, &DMA_InitStructure);

  // DMA Configuration for SPI Tx Event
  // (partly re-using previous DMA setup)
  DMA_Cmd(MIOS32_SPI1_DMA_TX_PTR, DISABLE);
  DMA_InitStructure.DMA_MemoryBaseAddr = 0; // will be configured later
  DMA_InitStructure.DMA_BufferSize = 0; // will be configured later
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_Init(MIOS32_SPI1_DMA_TX_PTR, &DMA_InitStructure);

  // enable SPI
  SPI_Cmd(MIOS32_SPI1_PTR, ENABLE);

  // enable SPI interrupts to DMA
  SPI_I2S_DMACmd(MIOS32_SPI1_PTR, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);

  // Configure DMA interrupt
  MIOS32_IRQ_Install(MIOS32_SPI1_DMA_IRQ_CHANNEL, MIOS32_IRQ_SPI_DMA_PRIORITY);

  // initial SPI peripheral configuration
  MIOS32_SPI_TransferModeInit(1, MIOS32_SPI_MODE_CLK1_PHASE1, MIOS32_SPI_PRESCALER_128);
#endif /* MIOS32_DONT_USE_SPI1 */


  ///////////////////////////////////////////////////////////////////////////
  // SPI2 (software emulated)
  ///////////////////////////////////////////////////////////////////////////
#ifndef MIOS32_DONT_USE_SPI2

  // disable callback function
  spi_callback[2] = NULL;

  // set RC pin(s) to 1
  MIOS32_SPI_RC_PinSet(2, 0, 1); // spi, rc_pin, pin_value
  MIOS32_SPI_RC_PinSet(2, 1, 1); // spi, rc_pin, pin_value

  // IO configuration
  MIOS32_SPI_IO_Init(2, MIOS32_SPI_PIN_DRIVER_WEAK_OD);

  // initial SPI peripheral configuration
  MIOS32_SPI_TransferModeInit(2, MIOS32_SPI_MODE_CLK1_PHASE1, MIOS32_SPI_PRESCALER_128);

#endif /* MIOS32_DONT_USE_SPI2 */

  return 0; // no error
}