Пример #1
0
/**************************************************************************//**
 * @brief
 *   Called on USB transfer completion callback for memory-mapped transfers.
 *   Will initiate a new transfer if there is more data available.
 *   If all data has been sent it will either send a CSW or stall the bulk-in
 *   endpoint if needed.
 *
 * @param[in] status
 *   The transfer status.
 *
 * @param[in] xferred
 *   Number of bytes actually transferred.
 *
 * @param[in] remaining
 *   Number of bytes not transferred.
 *
 * @return
 *   USB_STATUS_OK.
 *****************************************************************************/
static int XferBotDataCallback(USB_Status_TypeDef status,
                               uint32_t xferred, uint32_t remaining)
{
  (void) status;
  (void) remaining;

  pCmdStatus->xferLen   -= xferred;
  pCsw->dCSWDataResidue -= xferred;

  if (pCmdStatus->xferLen)
  {
    pCmdStatus->pData += xferred;
    UsbXferBotData(pCmdStatus->pData,
                   EFM32_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst),
                   XferBotDataCallback);
  }
  else
  {
    if (msdState == MSDD_SEND_CSW)
    {
      SendCsw();
      EnableNextCbw();
      msdState = MSDD_WAITFOR_CBW;
    }

    else if (msdState == MSDD_STALL_IN)
    {
      USBD_StallEp(BULK_IN);
      msdState = MSDD_WAIT_FOR_INUNSTALLED;
    }
  }

  return USB_STATUS_OK;
}
Пример #2
0
/**************************************************************************//**
 * @brief
 *   Serve the MSD state machine.
 *   This function should be called on a regular basis from your main loop.
 *   It cannot be called from within an interrupt handler.
 * @return
 *   Returns true if there is no pending tasks to perform. This means that
 *   energymodes (sleep) functionality can be used.
 *****************************************************************************/
bool MSDD_Handler(void)
{
  static uint32_t len;        /* Note: len is static ! */

  switch (msdState)
  {
  case MSDD_ACCESS_INDIRECT:
    if (pCmdStatus->xferLen)
    {
      len = EFM32_MIN(pCmdStatus->xferLen, pCmdStatus->maxBurst);

      msdState = MSDD_IDLE;
      if (pCmdStatus->direction)
      {
        MSDDMEDIA_Read(pCmdStatus, mediaBuffer, len / 512);
      }
      UsbXferBotData(mediaBuffer, len, XferBotDataIndirectCallback);
    }
    else
    {
      /* We are done ! */
      msdState = savedState;

      if (msdState == MSDD_SEND_CSW)
      {
        SendCsw();
        EnableNextCbw();
        msdState = MSDD_WAITFOR_CBW;
      }

      else if (msdState == MSDD_STALL_IN)
      {
        USBD_StallEp(BULK_IN);
        msdState = MSDD_WAIT_FOR_INUNSTALLED;
      }
    }
    break;

  case MSDD_WRITE_INDIRECT:
    MSDDMEDIA_Write(pCmdStatus, mediaBuffer, len / 512);
    pCmdStatus->lba += len / 512;
    msdState         = MSDD_ACCESS_INDIRECT;
    break;

  case MSDD_DO_CMD_TASK:
    if (pCbw->CBWCB[ 0 ] == SCSI_STARTSTOP_UNIT)
    {
      MSDDMEDIA_Flush();
    }
    /* else if ( .... )  Add more when needed. */
    SendCsw();
    EnableNextCbw();
    msdState = MSDD_WAITFOR_CBW;
    break;

  default:
    break;
  }
  return (msdState == MSDD_WAITFOR_CBW) || (msdState == MSDD_IDLE);
}
Пример #3
0
/**************************************************************************//**
 * @brief  Read touchscreen X or Y position (12bit resolution)
 * @param[in] ch X (ADC_X) or Y (ADC_Y) touchscreen readout
 * @return Touchscreen X or Y position
 *****************************************************************************/
static uint32_t getTouchChSample12bit( ADC_SingleInput_TypeDef ch )
{
  int i;
  uint32_t value, min, max, acc;

  if ( ch == ADC_X )
  {
    GPIO_PinModeSet(LCD_TOUCH_Y1, gpioModePushPull, 0);
    GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModePushPull, 1);
    GPIO_PinModeSet(LCD_TOUCH_X1, gpioModeInput, 0);
    GPIO_PinModeSet(LCD_TOUCH_X2, gpioModeInput, 0);
  }
  else
  {
    GPIO_PinModeSet(LCD_TOUCH_X1, gpioModePushPull, 1);
    GPIO_PinModeSet(LCD_TOUCH_X2, gpioModePushPull, 0);
    GPIO_PinModeSet(LCD_TOUCH_Y1, gpioModeInput, 0);
    GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModeInput, 0);
  }

  sInit.input = ch;
  ADC_InitSingle(ADC0, &sInit);

  delayUs( 10 );
  acc = 0;
  max = 0;
  min = 4096;
  for ( i=0; i<5; i++ )
  {
    value = readAdc();
    acc += value;
    min = EFM32_MIN( min, value );
    max = EFM32_MAX( max, value );
  }
  /* Throw away largest and smallest sample */
  acc = acc - min - max;
  /* Average */
  acc = acc / 3;

  if ( ch == ADC_X )
  {
    GPIO_PinModeSet(LCD_TOUCH_Y1, gpioModeInput, 0);
    GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModeInput, 0);
  }
  else
  {
    GPIO_PinModeSet(LCD_TOUCH_X1, gpioModeInput, 0);
    GPIO_PinModeSet(LCD_TOUCH_X2, gpioModeInput, 0);
  }

  return acc;
}
Пример #4
0
/**************************************************************************//**
 * @brief
 *   Start a USB bulk-in or bulk-out transfer to transfer a data payload
 *   to/from host according to the transfer mode of the transfer.
 *
 * @param[in] len
 *   Number of bytes to transfer.
 *****************************************************************************/
static void XferBotData(uint32_t length)
{
  pCmdStatus->xferLen   = length;
  pCsw->dCSWDataResidue = pCbw->dCBWDataTransferLength;

  if (pCmdStatus->xferType == XFER_INDIRECT)
  {
    /* Access media in "background" polling loop, i.e. in MSDD_Handler() */
    savedState = msdState;
    msdState   = MSDD_ACCESS_INDIRECT;
  }
  else
  {
    UsbXferBotData(pCmdStatus->pData,
                   EFM32_MIN(length, pCmdStatus->maxBurst),
                   XferBotDataCallback);
  }
}
Пример #5
0
static void rescheduleRtc( uint32_t rtcCnt )
{
  int i;
  uint64_t min = UINT64_MAX;

  // Find the timer with shortest timeout.
  for ( i = 0; i < EMDRV_RTCDRV_NUM_TIMERS; i++ ) {
    if (    ( timer[ i ].running   == true )
         && ( timer[ i ].remaining <  min  ) ) {
      min = timer[ i ].remaining;
    }
  }

  rtcRunning = false;
  if ( min != UINT64_MAX ) {
    min = EFM32_MIN( min, RTC_CLOSE_TO_MAX_VALUE );
#if defined( _EFM_DEVICE )
    if ( inTimerIRQ == false ) {
      lastStart = ( rtcCnt ) & RTC_COUNTER_MASK;
    } else
#endif
    {
      lastStart = rtcCnt;
    }
    RTC_INTCLEAR( RTC_COMP_INT );

    RTC_COMPARESET( rtcCnt + min );

#if defined( EMODE_DYNAMIC )
    // When RTC is running, we can not allow EM3 or EM4.
    if ( sleepBlocked == false ) {
      sleepBlocked = true;
      SLEEP_SleepBlockBegin( sleepEM3 );
    }
#endif

    rtcRunning = true;

    // Reenable compare IRQ.
    RTC_INTENABLE( RTC_COMP_INT );
  }
}
Пример #6
0
/**************************************************************************//**
 * @brief
 *   Parse a SCSI command.
 *   A minimal, yet sufficient SCSI command subset is supported.
 *****************************************************************************/
static void ProcessScsiCdb(void)
{
  MSDSCSI_Inquiry_TypeDef      *cbI;
  MSDSCSI_RequestSense_TypeDef *cbRS;
  MSDSCSI_ReadCapacity_TypeDef *cbRC;
  MSDSCSI_Read10_TypeDef       *cbR10;
  MSDSCSI_Write10_TypeDef      *cbW10;

  EFM32_ALIGN(4)
  static MSDSCSI_ReadCapacityData_TypeDef ReadCapData __attribute__ ((aligned(4)));

  pCmdStatus->valid    = false;
  pCmdStatus->xferType = XFER_MEMORYMAPPED;
  pCmdStatus->maxBurst = MAX_BURST;

  switch (pCbw->CBWCB[ 0 ])
  {
  case SCSI_INQUIRY:
    cbI = (MSDSCSI_Inquiry_TypeDef*) &pCbw->CBWCB;

    if ((cbI->Evpd == 0) && (cbI->PageCode == 0))
    {
      /* Standard Inquiry data request */
      pCmdStatus->valid     = true;
      pCmdStatus->direction = DIR_DATA_IN;
      pCmdStatus->pData     = (uint8_t*) &InquiryData;
      pCmdStatus->xferLen   = EFM32_MIN(SCSI_INQUIRYDATA_LEN,
                                        __REV16(cbI->AllocationLength));
    }
    break;

  case SCSI_REQUESTSENSE:
    cbRS = (MSDSCSI_RequestSense_TypeDef*) &pCbw->CBWCB;

    if ((cbRS->Desc == 0) && (cbRS->Reserved1 == 0) &&
        (cbRS->Reserved2 == 0) && (cbRS->Reserved3 == 0))
    {
      pCmdStatus->valid     = true;
      pCmdStatus->direction = DIR_DATA_IN;
      pCmdStatus->pData     = (uint8_t*) pSenseData;
      pCmdStatus->xferLen   = EFM32_MIN(SCSI_REQUESTSENSEDATA_LEN,
                                        cbRS->AllocationLength);
      pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &NoSenseData;
    }
    break;

  case SCSI_READCAPACITY:
    cbRC = (MSDSCSI_ReadCapacity_TypeDef*) &pCbw->CBWCB;

    if ((cbRC->Pmi == 0) && (cbRC->Lba == 0))
    {
      ReadCapData.LogicalBlockAddress = __REV(MSDDMEDIA_GetSectorCount() - 1);
      ReadCapData.LogicalBlockLength  = __REV(512);

      pCmdStatus->valid     = true;
      pCmdStatus->direction = DIR_DATA_IN;
      pCmdStatus->pData     = (uint8_t*) &ReadCapData;
      pCmdStatus->xferLen   = SCSI_READCAPACITYDATA_LEN;
    }
    break;

  case SCSI_READ10:
    cbR10 = (MSDSCSI_Read10_TypeDef*) &pCbw->CBWCB;

    pCmdStatus->direction = DIR_DATA_IN;
    pCmdStatus->valid     = MSDDMEDIA_CheckAccess(pCmdStatus,
                                                  __REV(cbR10->Lba),
                                                  __REV16(cbR10->TransferLength));
    break;

  case SCSI_WRITE10:
    cbW10 = (MSDSCSI_Write10_TypeDef*) &pCbw->CBWCB;

    pCmdStatus->direction = DIR_DATA_OUT;
    pCmdStatus->valid     = MSDDMEDIA_CheckAccess(pCmdStatus,
                                                  __REV(cbW10->Lba),
                                                  __REV16(cbW10->TransferLength));
    break;

  case SCSI_TESTUNIT_READY:
    pCmdStatus->valid     = true;
    pCmdStatus->direction = pCbw->Direction;
    pCmdStatus->xferLen   = 0;
    break;

  case SCSI_STARTSTOP_UNIT:
    pCmdStatus->valid     = true;
    pCmdStatus->direction = pCbw->Direction;
    pCmdStatus->xferLen   = 0;
    pCmdStatus->xferType  = XFER_INDIRECT;
    break;
  }

  if (!pCmdStatus->valid)
  {
    pCmdStatus->xferLen   = 0;
    pCmdStatus->direction = pCbw->Direction;
    pSenseData            = (MSDSCSI_RequestSenseData_TypeDef*) &IllegalSenseData;
  }
}
Пример #7
0
/***************************************************************************//**
 * @brief
 *    Start a timer.
 *
 * @note
 *    It is legal to start an already running timer.
 *
 * @param[in] id The id of the timer to start.
 * @param[in] type Timer type, oneshot or periodic. See @ref RTCDRV_TimerType_t.
 * @param[in] timeout Timeout expressed in milliseconds. If the timeout value
 *            is 0, the callback function will be called immediately and
 *            the timer will not be started.
 * @param[in] callback Function to call on timer expiry. See @ref
 *            RTCDRV_Callback_t. NULL is a legal value.
 * @param[in] user Extra callback function parameter for user application.
 *
 * @return
 *    @ref ECODE_EMDRV_RTCDRV_OK on success.@n
 *    @ref ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID if id has an illegal value.@n
 *    @ref ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED if the timer is not reserved.
 ******************************************************************************/
Ecode_t RTCDRV_StartTimer(  RTCDRV_TimerID_t id,
                            RTCDRV_TimerType_t type,
                            uint32_t timeout,
                            RTCDRV_Callback_t callback,
                            void *user )
{
  uint32_t timeElapsed, cnt, compVal, loopCnt = 0;
  uint32_t timeToNextTimerCompletion;

  // Check if valid timer ID.
  if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) {
    return ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID;
  }

  INT_Disable();
  if ( ! timer[ id ].allocated ) {
    INT_Enable();
    return ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED;
  }

  if ( timeout == 0 ) {
    if ( callback != NULL ) {
      callback( id, user );
    }
    INT_Enable();
    return ECODE_EMDRV_RTCDRV_OK;
  }

  cnt = RTC_COUNTERGET();

  timer[ id ].callback  = callback;
  timer[ id ].ticks     = MSEC_TO_TICKS( timeout );
  if (rtcdrvTimerTypePeriodic == type) {
    // Calculate compensation value for periodic timers.
    timer[ id ].periodicCompensationUsec = 1000 * timeout -
      (timer[ id ].ticks * TICK_TIME_USEC);
    timer[ id ].periodicDriftUsec = TICK_TIME_USEC/2;
  }
  // Add one tick in order to compensate if RTC is close to an increment event.
  timer[ id ].remaining = timer[ id ].ticks + 1;
  timer[ id ].running   = true;
  timer[ id ].timerType = type;
  timer[ id ].user      = user;

  if ( inTimerIRQ == true ) {
    // Exit now, remaining processing will be done in IRQ handler.
    INT_Enable();
    return ECODE_EMDRV_RTCDRV_OK;
  }

  // StartTimer() may recurse, keep track of recursion level.
  if ( startTimerNestingLevel < UINT32_MAX ) {
    startTimerNestingLevel++;
  }

  if ( rtcRunning == false ) {

#if defined( _EFM_DEVICE )
    lastStart = ( cnt ) & RTC_COUNTER_MASK;
#elif defined( _EFR_DEVICE )
    lastStart = cnt;
#endif

    RTC_INTCLEAR( RTC_COMP_INT );

    compVal = EFM32_MIN( timer[ id ].remaining, RTC_CLOSE_TO_MAX_VALUE );
    RTC_COMPARESET( cnt + compVal );

    // Start the timer system by enabling the compare interrupt.
    RTC_INTENABLE( RTC_COMP_INT );

#if defined( EMODE_DYNAMIC )
    // When RTC is running, we can not allow EM3 or EM4.
    if ( sleepBlocked == false ) {
      sleepBlocked = true;
      SLEEP_SleepBlockBegin( sleepEM3 );
    }
#endif

    rtcRunning = true;

  } else {

    // The timer system is running. We must stop, update timers with the time
    // elapsed so far, find the timer with the shortest timeout and then restart.
    // As StartTimer() may be called from the callbacks we only do this
    // processing at the first nesting level.
    if ( startTimerNestingLevel == 1  ) {

      timer[ id ].running = false;
      // This loop is repeated if CNT is incremented while processing.
      do {

        RTC_INTDISABLE( RTC_COMP_INT );

        timeElapsed = TIMEDIFF( cnt, lastStart );
#if defined( _EFM_DEVICE )
        // Compensate for the fact that CNT is normally COMP0+1 after a
        // compare match event.
        if ( timeElapsed == RTC_MAX_VALUE ) {
          timeElapsed = 0;
        }
#endif

        // Update all timers with elapsed time.
        checkAllTimers( timeElapsed );

        // Execute timer callbacks.
        executeTimerCallbacks();

        // Set timer to running only after checkAllTimers() is called once.
        if ( loopCnt == 0 ) {
          timer[ id ].running = true;
        }
        loopCnt++;

        // Restart RTC according to next timeout.
        rescheduleRtc( cnt );

        cnt = RTC_COUNTERGET();
        timeElapsed = TIMEDIFF( cnt, lastStart );
        timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );

        /* If the counter has passed the COMP(ARE) register value since we
           checked the timers, then we should recheck the timers and reschedule
           again. */
      }
      while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
    }
  }

  if ( startTimerNestingLevel > 0 ) {
    startTimerNestingLevel--;
  }

  INT_Enable();
  return ECODE_EMDRV_RTCDRV_OK;
}
Пример #8
0
/***************************************************************************//**
 * @brief
 *   Program the flash device.
 *
 * @note
 *   It is assumed that the area to be programmed is erased.
 *
 * @param[in] addr
 *   The first address in the flash to be programmed.
 *
 * @param[in] data
 *   Pointer to the data to be programmed.
 *
 * @param[in] count
 *   Number of bytes to be programmed.
 *
 * @return
 *   @ref NORFLASH_STATUS_OK on success, an error code enumerated in
 *   @ref NORFLASH_Status_TypeDef on failure.
 ******************************************************************************/
int NORFLASH_Program(uint32_t addr, uint8_t *data, uint32_t count)
{
  int      status;
  uint32_t sectorAddress, burst;

  if (!flashInitialized)
  {
    status = flashInterrogate();

    if (status != NORFLASH_STATUS_OK)
      return status;
  }

  if (!NORFLASH_AddressValid(addr) ||
      !NORFLASH_AddressValid(addr + count - 1))
  {
    EFM_ASSERT(false);
    return NORFLASH_INVALID_ADDRESS;
  }

  /* Check if odd byte aligned */
  if (addr & 1)
  {
    status = NORFLASH_ProgramByte(addr, *data);

    if (status != NORFLASH_STATUS_OK)
      return status;

    addr++;
    data++;
    count--;
  }

  while (count >= 2)
  {
#if 0     /* Traditional write method, write one word at a time */
    status = NORFLASH_ProgramWord16(addr, (*(data + 1) << 8) | *data);

    if (status != NORFLASH_STATUS_OK)
      return status;

    addr  += 2;
    data  += 2;
    count -= 2;

#else     /* "Write Buffer" write method */
    sectorAddress = addr & ~(flashInfo.sectorSize - 1);

    /* Max 32 "words" at a time, must not cross sector boundary */
    burst = EFM32_MIN(64U, sectorAddress + flashInfo.sectorSize - addr);
    burst = EFM32_MIN(burst, count & 0xFFFFFFFE);

    status = flashWriteBuffer(sectorAddress, addr, (uint16_t*) data, burst);

    if (status != NORFLASH_STATUS_OK)
      return status;

    addr  += burst;
    data  += burst;
    count -= burst;
#endif

  }

  /* Check if a trailing odd byte aligned value must be programmed */
  if (count)
  {
    status = NORFLASH_ProgramByte(addr, *data);
  }

  return status;
}