Example #1
0
File: main.c Project: perlfu/nxos
void main() {
    /* You can get the current time since bootup. The NXT does not
     * include a real time clock, so systick can only tell you the time
     * since bootup, not the "wall clock" time.
     */
    const U32 time_since_bootup = nx_systick_get_ms();

    /* You can use systick to wait for a specified time interval, either
     * in milliseconds or nanoseconds. The latter is used for very high
     * resolution timing loops, and should only really be useful to
     * drivers.
     */
    nx_systick_wait_ms(2000);
    nx_systick_wait_ns(42);

    /* At this point, system time is guaranteed to be greater than
     * before the wait calls. However, due to the way NxOS handles time,
     * more time than 2000ms + 42ns may have elapsed.
     */
    const U32 time_after_wait = nx_systick_get_ms();
    const U32 time_delta = time_after_wait - time_since_bootup;
    NX_ASSERT(time_delta > 2000);
}
Example #2
0
static void twi_isr(void)
{
  /* Read the status register once to acknowledge all TWI interrupts. */
  volatile U32 status = *AT91C_TWI_SR;

  /* Read mode and the status indicates a byte was received. */
  if (twi_state.mode == TWI_RX_BUSY && (status & AT91C_TWI_RXRDY)) {
    *twi_state.ptr = *AT91C_TWI_RHR;
    twi_state.ptr++;
    twi_state.len--;

    /* If only one byte is left to read, instruct the TWI to send a STOP
     * condition after the next byte.
     */
    if (twi_state.len == 1) {
      *AT91C_TWI_CR = AT91C_TWI_STOP;
    }

    /* If the read is over, inhibit all TWI interrupts and return to the
     * ready state.
     */
    if (twi_state.len == 0) {
      *AT91C_TWI_IDR = ~0;
      twi_state.mode = TWI_READY;
    }
  }

  /* Write mode and the status indicated a byte was transmitted. */
  if (twi_state.mode == TWI_TX_BUSY && (status & AT91C_TWI_TXRDY)) {
    /* If that was the last byte, inhibit TWI interrupts and return to
     * the ready state.
     */
    if (twi_state.len == 0) {
      *AT91C_TWI_IDR = ~0;
      twi_state.mode = TWI_READY;
    } else {
      /* Instruct the TWI to send a STOP condition at the end of the
       * next byte if this is the last byte.
       */
      if (twi_state.len == 1)
	*AT91C_TWI_CR = AT91C_TWI_STOP;

      /* Write the next byte to the transmit register. */
      *AT91C_TWI_THR = *twi_state.ptr;
      twi_state.ptr++;
      twi_state.len--;
    }
  }

  /* Check for error conditions. There are pretty critical failures,
   * since they indicate something is very wrong with either this
   * driver, or the coprocessor, or the hardware link between them.
   */
#if defined (__DBGENABLE__)
  /* Ignore Overruns and Underruns.
   * If JTAG debugging is enabled and the processor is halted, it
   * would skip the AVR communications until it is restarted.
   * (Technically it is not dependent on the __DBGENABLE__ compile flag).
   *
   * Nonetheless, the ARMDEBUG code may also cause some communications to be
   * missed, so it is safer to ignore these conditions as well when __DBGENABLE__
   * is defined.
   */
  if (status & (AT91C_TWI_NACK)) {
#else
  if (status & (AT91C_TWI_OVRE | AT91C_TWI_UNRE | AT91C_TWI_NACK)) {
#endif
	  *AT91C_TWI_CR = AT91C_TWI_STOP;
    *AT91C_TWI_IDR = ~0;
    twi_state.mode = TWI_FAILED;
    NX_FAIL("Lost link to AVR");
  }
}

void nx__twi_init(void)
{
  U32 clocks = 9;

  nx_interrupts_disable();

  /* Power up the TWI and PIO controllers. */
  *AT91C_PMC_PCER = (1 << AT91C_ID_TWI) | (1 << AT91C_ID_PIOA);

  /* Inhibit all TWI interrupt sources. */
  *AT91C_TWI_IDR = ~0;

  /* If the system is rebooting, the coprocessor might believe that it
   * is in the middle of an I2C transaction. Furthermore, it may be
   * pulling the data line low, in the case of a read transaction.
   *
   * The TWI hardware has a bug that will lock it up if it is
   * initialized when one of the clock or data lines is low.
   *
   * So, before initializing the TWI, we manually take control of the
   * pins using the PIO controller, and manually drive a few clock
   * cycles, until the data line goes high.
   */
  *AT91C_PIOA_MDER = AT91C_PA3_TWD | AT91C_PA4_TWCK;
  *AT91C_PIOA_PER = AT91C_PA3_TWD | AT91C_PA4_TWCK;
  *AT91C_PIOA_ODR = AT91C_PA3_TWD;
  *AT91C_PIOA_OER = AT91C_PA4_TWCK;

  while (clocks > 0 && !(*AT91C_PIOA_PDSR & AT91C_PA3_TWD)) {
    *AT91C_PIOA_CODR = AT91C_PA4_TWCK;
    nx_systick_wait_ns(1500);
    *AT91C_PIOA_SODR = AT91C_PA4_TWCK;
    nx_systick_wait_ns(1500);
    clocks--;
  }

  nx_interrupts_enable();

  /* Now that the I2C lines are clean, hand them back to the TWI
   * controller.
   */
  *AT91C_PIOA_PDR = AT91C_PA3_TWD | AT91C_PA4_TWCK;
  *AT91C_PIOA_ASR = AT91C_PA3_TWD | AT91C_PA4_TWCK;

  /* Reset the controller and configure its clock. The clock setting
   * makes the TWI run at 380kHz.
   */
  *AT91C_TWI_CR = AT91C_TWI_SWRST | AT91C_TWI_MSDIS;
  *AT91C_TWI_CWGR = 0x020f0f;
  *AT91C_TWI_CR = AT91C_TWI_MSEN;
  twi_state.mode = TWI_READY;

  /* Install the TWI interrupt handler. */
  nx_aic_install_isr(AT91C_ID_TWI, AIC_PRIO_RT, AIC_TRIG_LEVEL, twi_isr);
}