Beispiel #1
0
void main ()
{
  hBSP430halPORT b0hal = hBSP430portLookup(BSP430_PLATFORM_BUTTON0_PORT_PERIPH_HANDLE);
  volatile sBSP430hplPORTIE * b0hpl;
  int b0pin = iBSP430portBitPosition(BSP430_PLATFORM_BUTTON0_PORT_BIT);

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();

  cprintf("\nbutton " __DATE__ " " __TIME__ "\n");

  cprintf("There's supposed to be a button at %s.%u\n",
          xBSP430portName(BSP430_PLATFORM_BUTTON0_PORT_PERIPH_HANDLE),
          b0pin);
  if (! b0hal) {
    cprintf("Whoops, guess it's not really there\n");
    return;
  }
  b0hpl = BSP430_PORT_HAL_GET_HPL_PORTIE(b0hal);
  button_state.button_cb.next_ni = b0hal->pin_cbchain_ni[b0pin];
  b0hal->pin_cbchain_ni[b0pin] = &button_state.button_cb;
  b0hpl->sel &= ~BSP430_PLATFORM_BUTTON0_PORT_BIT;
  b0hpl->dir &= ~BSP430_PLATFORM_BUTTON0_PORT_BIT;
#if (BSP430_PORT_SUPPORTS_REN - 0)
  BSP430_PORT_HAL_SET_REN(b0hal, BSP430_PLATFORM_BUTTON0_PORT_BIT, BSP430_PORT_REN_PULL_UP);
#endif /* BSP430_PORT_SUPPORTS_REN */
  if (b0hpl->in & BSP430_PLATFORM_BUTTON0_PORT_BIT) {
    button_state.in_mask = BSP430_PLATFORM_BUTTON0_PORT_BIT;
    b0hpl->ies |= BSP430_PLATFORM_BUTTON0_PORT_BIT;
  } else {
    button_state.in_mask = 0;
    b0hpl->ies &= ~BSP430_PLATFORM_BUTTON0_PORT_BIT;
  }
  b0hpl->ifg &= ~BSP430_PLATFORM_BUTTON0_PORT_BIT;
  b0hpl->ie |= BSP430_PLATFORM_BUTTON0_PORT_BIT;
  cprintf("Button is configured.  Try pressing it.  No debouncing is done.\n");
#if ! (configBSP430_CORE_LPM_EXIT_CLEAR_GIE - 0)
  cprintf("WARNING: Interrupts remain enabled after wakeup\n");
#endif /* configBSP430_CORE_LPM_EXIT_CLEAR_GIE */

  vBSP430ledSet(0, 1);

  while (1) {
    static const char * state_str[] = { "released", "pressed" };

    cprintf("Count %u, in mask 0x%02x: %s\n", button_state.count, button_state.in_mask, state_str[!button_state.in_mask]);

    /* Note that we've never turned interrupts on, but
     * BSP430_CORE_LPM_ENTER_NI() does so internally so the ISR can be
     * executed.  Whether they are cleared before returning to this
     * loop depends on #configBSP430_CORE_LPM_EXIT_CLEAR_GIE. */
    BSP430_CORE_LPM_ENTER_NI(LPM0_bits);
#if ! (configBSP430_CORE_LPM_EXIT_CLEAR_GIE - 0)
    /* Infrastructure didn't clear this, so we should */
    BSP430_CORE_DISABLE_INTERRUPT();
#endif /* configBSP430_CORE_LPM_EXIT_CLEAR_GIE */
  }
}
Beispiel #2
0
void main ()
{
  hBSP430halSERIAL i2c;
  sBSP430bq24210 bq24210;
  union {
    sBQ27510 state;
    uint16_t raw[1];
  } u;
  const int nwords = sizeof(u.state)/sizeof(u.raw[0]);
  unsigned long resample_interval_utt;
  unsigned long resample_wake_utt;
  unsigned int flags;
  int rc;

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();

  cprintf("\nbattpack " __DATE__ " " __TIME__ "\n");

  bq24210.chg_port = xBSP430hplLookupPORT(APP_CHGn_PORT_PERIPH_HANDLE);
  bq24210.en_port = xBSP430hplLookupPORT(APP_ENn_PORT_PERIPH_HANDLE);
  bq24210.pg_port = xBSP430hplLookupPORT(APP_PGn_PORT_PERIPH_HANDLE);
  bq24210.chg_bit = APP_CHGn_PORT_BIT;
  bq24210.en_bit = APP_ENn_PORT_BIT;
  bq24210.pg_bit = APP_PGn_PORT_BIT;

  cprintf("CHGn on %s.%u\n",
          xBSP430portName(xBSP430periphFromHPL(bq24210.chg_port)),
          iBSP430portBitPosition(bq24210.chg_bit));
  cprintf("ENn on %s.%u\n",
          xBSP430portName(xBSP430periphFromHPL(bq24210.en_port)),
          iBSP430portBitPosition(bq24210.en_bit));
  cprintf("PGn on %s.%u\n",
          xBSP430portName(xBSP430periphFromHPL(bq24210.pg_port)),
          iBSP430portBitPosition(bq24210.pg_bit));
  if (! (bq24210.chg_port && bq24210.en_port && bq24210.pg_port)) {
    cprintf("One of the ports is missing\n");
    return;
  }

  /* Charge signal is an input (active low) to the MCU.  Configure as
   * input with internal pull-up. */
  bq24210.chg_port->dir &= ~bq24210.chg_bit;
  bq24210.chg_port->out |= bq24210.chg_bit;
  bq24210.chg_port->ren |= bq24210.chg_bit;

  /* Power-good signal is an input (active low) to the MCU.  Configure
   * as input with internal pull-up. */
  bq24210.pg_port->dir &= ~bq24210.pg_bit;
  bq24210.pg_port->out |= bq24210.pg_bit;
  bq24210.pg_port->ren |= bq24210.pg_bit;

  /* Enable signal is an output (active low) from the MCU.  Start
   * active. */
  bq24210.en_port->out &= ~bq24210.en_bit;
  bq24210.en_port->dir |= bq24210.en_bit;

  cprintf("I2C on %s at address 0x%02x\nPins: %s\n",
          xBSP430serialName(APP_BQ27510_I2C_PERIPH_HANDLE),
          APP_BQ27510_I2C_ADDRESS,
          xBSP430platformPeripheralHelp(APP_BQ27510_I2C_PERIPH_HANDLE, BSP430_PERIPHCFG_SERIAL_I2C));

  /* NOTE: At default BSP430_SERIAL_I2C_BUS_SPEED_HZ 400kHz this
   * devices supports only single-byte write operations.  Further,
   * ensure a 66us delay between packets. */
  i2c = hBSP430serialOpenI2C(hBSP430serialLookup(APP_BQ27510_I2C_PERIPH_HANDLE),
                             BSP430_SERIAL_ADJUST_CTL0_INITIALIZER(UCMST),
                             0, 0);
  if (! i2c) {
    cprintf("I2C open failed\n");
    return;
  }
  (void)iBSP430i2cSetAddresses_rh(i2c, -1, APP_BQ27510_I2C_ADDRESS);

  resample_interval_utt = BSP430_UPTIME_MS_TO_UTT(1000UL * RESAMPLE_INTERVAL_S);
  resample_wake_utt = ulBSP430uptime_ni();
  flags = FLG_DUMP_STATE | FLG_UPDATE_INTERVAL;

  BSP430_CORE_ENABLE_INTERRUPT();
  while (1) {
    char astext_buf[BSP430_UPTIME_AS_TEXT_LENGTH];
    uint16_t temperature_dC;

    if (FLG_DUMP_STATE & flags) {
      memset(&u, 0, sizeof(u));
      rc = readBQ27510(i2c, 0, nwords, u.raw);
      cprintf("Device ID %04x rc %d\n", u.state.device_id, rc);
      cprintf("%.30s = %d\n", "atRate_mA", u.state.atRate_mA);
      cprintf("%.30s = %u\n", "atRatetimeToEmpty_min", u.state.atRatetimeToEmpty_min);
      cprintf("%.30s = %u\n", "temperature_dK", u.state.temperature_dK);
      cprintf("%.30s = %u\n", "voltage_mV", u.state.voltage_mV);
      cprintf("%.30s = 0x%04x\n", "flags", u.state.flags);
      cprintf("%.30s = %u\n", "nominalAvailableCapacity_mAh", u.state.nominalAvailableCapacity_mAh);
      cprintf("%.30s = %u\n", "fullAvailableCapacity_mAh", u.state.fullAvailableCapacity_mAh);
      cprintf("%.30s = %u\n", "remainingCapacity_mAh", u.state.remainingCapacity_mAh);
      cprintf("%.30s = %u\n", "fullChargeCapacity_mAh", u.state.fullChargeCapacity_mAh);
      cprintf("%.30s = %d\n", "averageCurrent_mA", u.state.averageCurrent_mA);
      cprintf("%.30s = %u\n", "timeToEmpty_min", u.state.timeToEmpty_min);
      cprintf("%.30s = %d\n", "standbyCurrent_mA", u.state.standbyCurrent_mA);
      cprintf("%.30s = %u\n", "standbyTimeToEmpty_min", u.state.standbyTimeToEmpty_min);
      cprintf("%.30s = %u\n", "stateOfHealth_ppcpx", u.state.stateOfHealth_ppcpx);
      cprintf("%.30s = %u\n", "cycleCount", u.state.cycleCount);
      cprintf("%.30s = %u\n", "stateOfCharge_ppc", u.state.stateOfCharge_ppc);
      cprintf("%.30s = %d\n", "instantaneousCurrent_mA", u.state.instantaneousCurrent_mA);
      cprintf("%.30s = %u\n", "internalTemperature_dK", u.state.internalTemperature_dK);
      cprintf("%.30s = %u\n", "reistanceScale", u.state.reistanceScale);
      cprintf("%.30s = %u\n", "operationConfiguration", u.state.operationConfiguration);
      cprintf("%.30s = %u\n", "designCapacity_mAh", u.state.designCapacity_mAh);
      cprintf("flags %02x ; ENn state %d\n", flags, (bq24210.en_port->out & bq24210.en_bit));
      flags &= ~FLG_DUMP_STATE;
    }
    if (FLG_TOGGLE_ENABLE & flags) {
      bq24210.en_port->out ^= bq24210.en_bit;
      flags &= ~FLG_TOGGLE_ENABLE;
    }
    vBSP430ledSet(BSP430_LED_GREEN, !(bq24210.en_port->out & bq24210.en_bit));

    rc = readBQ27510(i2c, 0, nwords, u.raw);
    temperature_dC = u.state.temperature_dK - 2733;

    cprintf("%s: %c%c%c % 2d.%dC  %4dmV ; SoC %u%% ; Cap %4d / %4d ; %dmA ~ %dmA / %u\n",
            xBSP430uptimeAsText(ulBSP430uptime(), astext_buf),
            (bq24210.en_port->out & bq24210.en_bit) ? ' ' : 'E',
            (bq24210.chg_port->in & bq24210.chg_bit) ? ' ' : 'C',
            (bq24210.pg_port->in & bq24210.pg_bit) ? ' ' : 'P',
            (temperature_dC / 10), (temperature_dC % 10),
            u.state.voltage_mV,
            u.state.stateOfCharge_ppc,
            u.state.remainingCapacity_mAh,
            u.state.fullAvailableCapacity_mAh,
            u.state.instantaneousCurrent_mA,
            u.state.averageCurrent_mA,
            u.state.cycleCount
            );
    if (FLG_UPDATE_INTERVAL & flags) {
      resample_wake_utt += resample_interval_utt;
      flags &= ~FLG_UPDATE_INTERVAL;
    }
    flags = 0;
    while (! flags) {
      iBSP430consoleFlush();
      if (0 >= lBSP430uptimeSleepUntil(resample_wake_utt, LPM3_bits)) {
        flags |= FLG_UPDATE_INTERVAL;
      }
      while (0 <= ((rc = cgetchar()))) {
        if ('!' == rc) {
          flags |= FLG_TOGGLE_ENABLE;
        } else if (' ' == rc) {
          flags |= FLG_DUMP_STATE;
        }
      }
    }

  }
}
Beispiel #3
0
void main ()
{
  int rc = 0;

  /* GDO0 and GDO2 are always interrupt-capable. */
  volatile sBSP430hplPORTIE * gdo0 = xBSP430hplLookupPORTIE(BSP430_RF_CC110X_GDO0_PORT_PERIPH_HANDLE);
  volatile sBSP430hplPORTIE * gdo2 = xBSP430hplLookupPORTIE(BSP430_RF_CC110X_GDO2_PORT_PERIPH_HANDLE);
  hBSP430halPORT hgdo1 = hBSP430portLookup(BSP430_RF_CC110X_GDO1_PORT_PERIPH_HANDLE);
  hBSP430halPORT hcsn = hBSP430portLookup(BSP430_RF_CC110X_CSn_PORT_PERIPH_HANDLE);

  spi = hBSP430serialLookup(BSP430_RF_CC110X_SPI_PERIPH_HANDLE);

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();
  cprintf("\nccid " __DATE__ " " __TIME__ "\n");

  cprintf("GDO0 %p at %s.%u\n", gdo0, xBSP430portName(BSP430_RF_CC110X_GDO0_PORT_PERIPH_HANDLE), iBSP430portBitPosition(BSP430_RF_CC110X_GDO0_PORT_BIT));
  cprintf("GDO1 HAL %p HPL %p at %s.%u\n", hgdo1, hgdo1->hpl.any, xBSP430portName(BSP430_RF_CC110X_GDO1_PORT_PERIPH_HANDLE), iBSP430portBitPosition(BSP430_RF_CC110X_GDO1_PORT_BIT));
  cprintf("GDO2 %p at %s.%u\n", gdo2, xBSP430portName(BSP430_RF_CC110X_GDO2_PORT_PERIPH_HANDLE), iBSP430portBitPosition(BSP430_RF_CC110X_GDO2_PORT_BIT));
  cprintf("CSn HAL %p HPL %p at %s.%u\n", hcsn, hcsn->hpl.any, xBSP430portName(BSP430_RF_CC110X_CSn_PORT_PERIPH_HANDLE), iBSP430portBitPosition(BSP430_RF_CC110X_CSn_PORT_BIT));
  cprintf("SPI %p is %s\n", spi, xBSP430serialName(BSP430_RF_CC110X_SPI_PERIPH_HANDLE));
#if BSP430_PLATFORM_PERIPHERAL_HELP
  cprintf("SPI Pins: %s\n", xBSP430platformPeripheralHelp(BSP430_RF_CC110X_SPI_PERIPH_HANDLE, BSP430_PERIPHCFG_SERIAL_SPI3));
#endif /* BSP430_PLATFORM_PERIPHERAL_HELP */
  cprintf(__DATE__ " " __TIME__ "\n");


  /* Configure the SPI interface, but immediately put it into hold
   * mode so we can check CHIP_RDYn on the MISO/GDO1 input. */
  spi = hBSP430serialOpenSPI(spi, BSP430_RF_CC110X_SPI_CTL0_BYTE, 0, 0);
  if (spi) {
    rc = iBSP430serialSetHold_rh(spi, 1);
    /* GDO1 to input, pull-up */
    BSP430_PORT_HAL_HPL_DIR(hgdo1) &= ~BSP430_RF_CC110X_GDO1_PORT_BIT;
    BSP430_PORT_HAL_SET_REN(hgdo1, BSP430_RF_CC110X_GDO1_PORT_BIT, BSP430_PORT_REN_PULL_UP);
  }

  cprintf("SPI device %p hold returned %d\n", spi, rc);
  if (! spi) {
    return;
  }

  /* Configure CSn initial high to ensure we have a falling edge when
   * we first enable the radio. */
  BSP430_PORT_HAL_HPL_SEL(hcsn) &= ~BSP430_RF_CC110X_CSn_PORT_BIT;
  BSP430_PORT_HAL_HPL_OUT(hcsn) |= BSP430_RF_CC110X_CSn_PORT_BIT;
  BSP430_PORT_HAL_HPL_DIR(hcsn) |= BSP430_RF_CC110X_CSn_PORT_BIT;

  /* Now enable the radio */
  BSP430_PORT_HAL_HPL_OUT(hcsn) &= ~BSP430_RF_CC110X_CSn_PORT_BIT;

  /* Spin until GDO1 (CHP_RDYn) is clear indicating radio is responsive */
  while (BSP430_PORT_HAL_HPL_IN(hgdo1) & BSP430_RF_CC110X_GDO1_PORT_BIT) {
    cprintf("Waiting for radio ready\n");
    BSP430_CORE_DELAY_CYCLES(BSP430_CLOCK_NOMINAL_MCLK_HZ);
  }

  /* Enable SPI */
  rc = iBSP430serialSetHold_rh(spi, 0);
  cprintf("Radio is up, hold release %d; sending SRES strobe\n", rc);

  /* Send a reset */
  do {
    rc = sendStrobe(0x30);
    cprintf("Strobe response %#02x\n", rc);
    if (0x0F != rc) {
      BSP430_CORE_DELAY_CYCLES(BSP430_CLOCK_NOMINAL_MCLK_HZ);
    }
  } while (0x0F != rc);

  cprintf("PARTNUM response %#02x\n", readRegister(0x30));
  cprintf("VERSION response %#02x\n", readRegister(0x31));
  cprintf("IOCFG2 read %#02x\n", readRegister(0x00));
  cprintf("IOCFG1 read %#02x\n", readRegister(0x01));
  cprintf("IOCFG0 read %#02x\n", readRegister(0x02));

  /* ChipCon radios consume 1.4mA when idle.  That goes down to
   * nominally 400 nA if the GDOs are configured to "HW to 0" and the
   * chip is told to power-down on loss of CSn.  On the EXP430F5438
   * the RF PWR header indicates that a CC1101 is using 40 nA in this
   * mode.*/
  rc = writeRegister(0x00, 0x2f);
  rc = writeRegister(0x01, 0x2f);
  rc = writeRegister(0x02, 0x2f);
  cprintf("Cleared IOCFG\n");
  cprintf("IOCFG2 read %#02x\n", readRegister(0x00));
  cprintf("IOCFG1 read %#02x\n", readRegister(0x01));
  cprintf("IOCFG0 read %#02x\n", readRegister(0x02));

  /* SPWD */
  rc = sendStrobe(0x39);
  cprintf("SPWD got %d\n", rc);

  /* Disable SPI before removing CSn otherwise the sequence isn't
   * right. */
  rc = iBSP430serialSetHold_rh(spi, 1);
  BSP430_PORT_HAL_HPL_OUT(hcsn) |= BSP430_RF_CC110X_CSn_PORT_BIT;

  /* This gets the RF2500T power down to about 120 nA.  Note:
   * Purposefully enter LPM with #GIE off since we do not intend to
   * wake up.*/
  BSP430_CORE_LPM_ENTER(LPM3_bits);
}
Beispiel #4
0
void main ()
{
  sBSP430halPORT * port_hal;
  hBSP430halTIMER hal;
  volatile sBSP430hplTIMER * hpl;

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();
  cputchar('\n');
  BSP430_CORE_DELAY_CYCLES(BSP430_CLOCK_NOMINAL_MCLK_HZ / 1000);

  cprintf("\n\nsynccap " __DATE__ " " __TIME__ "\n");
  cprintf("External input on %s.%u corresponds to %s.%u%c\n",
          xBSP430portName(BSP430_TIMER_CCACLK_CC1_PORT_PERIPH_HANDLE),
          bitToPin(BSP430_TIMER_CCACLK_CC1_PORT_BIT),
          xBSP430timerName(BSP430_TIMER_CCACLK_PERIPH_HANDLE),
          PORT_CCIDX,
          'A' + (BSP430_TIMER_CCACLK_CC1_CCIS / CCIS0));
  port_hal = hBSP430portLookup(BSP430_TIMER_CCACLK_CC1_PORT_PERIPH_HANDLE);
  if (NULL == port_hal) {
    cprintf("Port HAL not available\n");
    return;
  }
  hal = hBSP430timerLookup(BSP430_TIMER_CCACLK_PERIPH_HANDLE);
  if (NULL == hal) {
    cprintf("Can't find timer\n");
    return;
  }

  BSP430_PORT_HAL_HPL_DIR(port_hal) &= ~BSP430_TIMER_CCACLK_CC1_PORT_BIT;
  BSP430_PORT_HAL_HPL_SEL(port_hal) |= BSP430_TIMER_CCACLK_CC1_PORT_BIT;
  hpl = hal->hpl;
  hpl->cctl[1] = CM_3 | BSP430_TIMER_CCACLK_CC1_CCIS | SCS | CAP | CCIE;
  captured.last_cci = !!(hpl->cctl[1] & CCI);
  BSP430_HAL_ISR_CALLBACK_LINK_NI(sBSP430halISRIndexedChainNode,
                                  hal->cc_cbchain_ni[PORT_CCIDX],
                                  captured.cb,
                                  next_ni);
  hpl->ctl = TASSEL_2 | MC_2 | TACLR | TAIE;

  /* Need to enable interrupts so timer overflow events are properly
   * acknowledged */
  while (1) {
    unsigned int ccr;
    unsigned int cctl;
    unsigned int count;
    unsigned int errors;
    int last_cci;
    unsigned long event_tt;

    BSP430_CORE_DISABLE_INTERRUPT();
    do {
      event_tt = captured.event_tt;
      captured.event_tt = 0;
      count = captured.count;
      errors = captured.errors;
      captured.count = 0;
      captured.errors = 0;
      last_cci = captured.last_cci;
      cctl = hpl->cctl[PORT_CCIDX];
      ccr = hpl->ccr[PORT_CCIDX];
      hpl->cctl[PORT_CCIDX] &= ~COV;
    } while (0);
    BSP430_CORE_ENABLE_INTERRUPT();

    cprintf("Up %lu ACLK ticks, timer %lu event %lx ccr %x cctl %04x\n"
            "\tCCI %d SCCI %d COV %d ; recorded CCI %d ; count %u errors %d\n",
            ulBSP430uptime(),
            ulBSP430timerCounter(hal, NULL),
            event_tt,
            ccr,
            cctl,
            !!(cctl & CCI), !!(cctl & SCCI), !!(cctl & COV), last_cci, count, errors);
    BSP430_CORE_DELAY_CYCLES(BSP430_CLOCK_NOMINAL_MCLK_HZ);
  }
}
Beispiel #5
0
void main ()
{
  volatile sBSP430hplTIMER * const timer_hpl = xBSP430hplLookupTIMER(BSP430_TIMER_CCACLK_PERIPH_HANDLE);
  unsigned int outclk;
  unsigned int last_outclk;
  unsigned int cctl;
  hBSP430halPORT const inclk_port_hal = hBSP430portLookup(BSP430_TIMER_CCACLK_CLK_PORT_PERIPH_HANDLE);
  hBSP430halPORT const cc_port_hal = hBSP430portLookup(APP_CC_PORT_PERIPH_HANDLE);
  hBSP430halPORT const outclk_port_hal = hBSP430portLookup(APP_OUTCLK_PORT_PERIPH_HANDLE);
  hBSP430halPORT const trigger_port_hal = hBSP430portLookup(APP_TRIGGER_PORT_PERIPH_HANDLE);
  vBSP430platformInitialize_ni();
  vBSP430unittestInitialize();

  cprintf("timer_scs_test: " __DATE__ " " __TIME__ "\n");
  if (NULL == timer_hpl) {
    cprintf("ERROR: Unable to get timer HPL access\n");
    return;
  }
  if (NULL == inclk_port_hal) {
    cprintf("ERROR: Unable to get INCLK port access\n");
    return;
  }
  if (NULL == cc_port_hal) {
    cprintf("ERROR: Unable to get CC0 port access\n");
    return;
  }
  if (NULL == outclk_port_hal) {
    cprintf("ERROR: Unable to get OUTCLK port access\n");
    return;
  }
  if (NULL == trigger_port_hal) {
    cprintf("ERROR: Unable to get TRIGGER port access\n");
    return;
  }
  cprintf("Please connect OUTCLK at %s.%u to %s INCLK at %s.%u\n",
          xBSP430portName(APP_OUTCLK_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(APP_OUTCLK_PORT_BIT),
          xBSP430timerName(BSP430_TIMER_CCACLK_PERIPH_HANDLE),
          xBSP430portName(BSP430_TIMER_CCACLK_CLK_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(BSP430_TIMER_CCACLK_CLK_PORT_BIT));
  cprintf("Please connect TRIGGER at %s.%u to %s CCI0%c at %s.%u\n",
          xBSP430portName(APP_TRIGGER_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(APP_TRIGGER_PORT_BIT),
          xBSP430timerName(BSP430_TIMER_CCACLK_PERIPH_HANDLE),
          'A' + (APP_CC_CCIS / CCIS0),
          xBSP430portName(APP_CC_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(APP_CC_PORT_BIT));

  /* OUTCLK: output low */
  outclk = 0;
  BSP430_PORT_HAL_HPL_OUT(outclk_port_hal) &= ~APP_OUTCLK_PORT_BIT;
  BSP430_PORT_HAL_HPL_DIR(outclk_port_hal) |= APP_OUTCLK_PORT_BIT;
  BSP430_PORT_HAL_HPL_SEL(outclk_port_hal) &= ~APP_OUTCLK_PORT_BIT;

  /* TRIGGER: output low */
  BSP430_PORT_HAL_HPL_OUT(trigger_port_hal) &= ~APP_TRIGGER_PORT_BIT;
  BSP430_PORT_HAL_HPL_DIR(trigger_port_hal) |= APP_TRIGGER_PORT_BIT;
  BSP430_PORT_HAL_HPL_SEL(trigger_port_hal) &= ~APP_TRIGGER_PORT_BIT;

  /* INCLK: input peripheral function */
  BSP430_PORT_HAL_HPL_SEL(inclk_port_hal) &= ~BSP430_TIMER_CCACLK_CLK_PORT_BIT;
  BSP430_PORT_HAL_HPL_SEL(inclk_port_hal) |= BSP430_TIMER_CCACLK_CLK_PORT_BIT;

  /* CC0: input peripheral function */
  BSP430_PORT_HAL_HPL_DIR(cc_port_hal) &= ~APP_CC_PORT_BIT;
  BSP430_PORT_HAL_HPL_SEL(cc_port_hal) |= APP_CC_PORT_BIT;
  cprintf("P4: DIR %04x SEL %04x\n", P4DIR, P4SEL);

#define CLEAR_CAPTURE() do {                    \
    timer_hpl->cctl[APP_CCIDX] &= ~CCIFG;                 \
    timer_hpl->ccr[APP_CCIDX] = 0;                        \
  } while (0)

#define ASSERT_CLOCK_HIGH() do {                                        \
    BSP430_UNITTEST_ASSERT_TRUE(BSP430_PORT_HAL_HPL_OUT(outclk_port_hal) & APP_OUTCLK_PORT_BIT); \
  } while (0)

#define ASSERT_CLOCK_LOW() do {                                         \
    BSP430_UNITTEST_ASSERT_FALSE(BSP430_PORT_HAL_HPL_OUT(outclk_port_hal) & APP_OUTCLK_PORT_BIT); \
  } while (0)

#define ASSERT_CCI_HIGH() do {                              \
    BSP430_UNITTEST_ASSERT_TRUE(CCI & timer_hpl->cctl[APP_CCIDX]);        \
  } while (0)

#define ASSERT_CCI_LOW() do {                                \
    BSP430_UNITTEST_ASSERT_FALSE(CCI & timer_hpl->cctl[APP_CCIDX]);        \
  } while (0)

#define ASSERT_INTERNAL_TRIGGER_HIGH() do {                             \
    BSP430_UNITTEST_ASSERT_TRUE(CCIS_3 == (CCIS_3 & timer_hpl->cctl[APP_CCIDX])); \
  } while (0)

#define ASSERT_INTERNAL_TRIGGER_LOW() do {                              \
    BSP430_UNITTEST_ASSERT_TRUE(CCIS_2 == (CCIS_3 & timer_hpl->cctl[APP_CCIDX])); \
  } while (0)

#define ASSERT_NO_CAPTURE() do {                                \
    BSP430_UNITTEST_ASSERT_FALSE(CCIFG & timer_hpl->cctl[APP_CCIDX]);     \
    BSP430_UNITTEST_ASSERT_EQUAL_FMTx(0, timer_hpl->ccr[APP_CCIDX]);      \
  } while (0)

#define ASSERT_YES_CAPTURE() do {                                       \
    BSP430_UNITTEST_ASSERT_TRUE(CCIFG & timer_hpl->cctl[APP_CCIDX]);              \
    BSP430_UNITTEST_ASSERT_EQUAL_FMTx(timer_hpl->r, timer_hpl->ccr[APP_CCIDX]);   \
  } while (0)

  /* Capture asynchronously on falling edge from TRIGGER. */
  timer_hpl->ccr[APP_CCIDX] = 0;
  timer_hpl->cctl[APP_CCIDX] = CM_2 | APP_CC_CCIS | SCCI | CAP;
  timer_hpl->cctl[APP_CCIDX] = CM_3 | APP_CC_CCIS | SCCI | CAP;
  cprintf("%u: Timer: R %04x CTL %04x CCR %04x CCTL %04x\n", __LINE__, timer_hpl->r, timer_hpl->ctl, timer_hpl->ccr[APP_CCIDX], timer_hpl->cctl[APP_CCIDX]);

  /* Count upwards. */
  timer_hpl->ctl = TASSEL_0 | MC_2 | TACLR;

  /* Validate that we can control the clock input. */
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, 0);
  ASSERT_CLOCK_LOW();
  HALF_TICK_OUTCLK();
  ASSERT_CLOCK_HIGH();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, 1);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  HALF_TICK_OUTCLK();
  ASSERT_CLOCK_LOW();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, 1);
  HALF_TICK_OUTCLK();
  ASSERT_CLOCK_HIGH();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  HALF_TICK_OUTCLK();
  ASSERT_CLOCK_LOW();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);

  /* Verify that we can control the trigger, and that asynchronous
   * captures work. */
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_LOW();
  HALF_TRIGGER();
  if (CM0 & timer_hpl->cctl[APP_CCIDX]) {
    ASSERT_YES_CAPTURE();
    if (! (CM1 & timer_hpl->cctl[APP_CCIDX])) {
      CLEAR_CAPTURE();
    }
  } else {
    ASSERT_NO_CAPTURE();
  }
  ASSERT_CCI_HIGH();
  HALF_TRIGGER();
  ASSERT_YES_CAPTURE();
  ASSERT_CCI_LOW();
  CLEAR_CAPTURE();

  /* Advance the clock.  Make sure no capture occurred. */
  last_outclk = outclk;
  HALF_TICK_OUTCLK();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, last_outclk+1);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  ASSERT_NO_CAPTURE();
  last_outclk = outclk;
  HALF_TICK_OUTCLK();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(last_outclk, timer_hpl->r);
  ASSERT_NO_CAPTURE();

  /* Now turn on synchronous capture */
  timer_hpl->cctl[APP_CCIDX] |= SCS;

  /* Advance the clock.  Make sure no capture occurred */
  cctl = timer_hpl->cctl[APP_CCIDX];
  last_outclk = outclk;
  ASSERT_CLOCK_LOW();
  HALF_TICK_OUTCLK();
  ASSERT_CLOCK_HIGH();
  ASSERT_NO_CAPTURE();
  HALF_TICK_OUTCLK();
  ASSERT_CLOCK_LOW();
  ASSERT_NO_CAPTURE();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(last_outclk+1, timer_hpl->r);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(cctl, timer_hpl->cctl[APP_CCIDX]);

  /* Do this again to make really sure no capture occurred. */
  HALF_TICK_OUTCLK();
  ASSERT_NO_CAPTURE();
  HALF_TICK_OUTCLK();
  ASSERT_NO_CAPTURE();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(last_outclk+2, timer_hpl->r);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(cctl, timer_hpl->cctl[APP_CCIDX]);

  /*
  F1) CCI rises then falls while CLK remains low.  CCIFG remains low.  When CLK
  rises the counter is incremented but CCIFG remains low.  CCIFG is set only
  when CLK falls.
  */

  /* CLK is low. */
  ASSERT_CLOCK_LOW();

  /* Check that external triggers with sync async do not trigger when
   * clock does not advance. */
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_LOW();
  HALF_TRIGGER();
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_HIGH();
  HALF_TRIGGER();
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_LOW();

  /* Advance the clock.  No action on rising edge. */
  last_outclk = outclk;
  HALF_TICK_OUTCLK();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, last_outclk+1);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_LOW();
  ASSERT_CLOCK_HIGH();

  /* Falling edge does not increment counter but does cause capture */
  last_outclk = outclk;
  HALF_TICK_OUTCLK();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, last_outclk);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  ASSERT_YES_CAPTURE();
  ASSERT_CCI_LOW();
  CLEAR_CAPTURE();

  /*
  F2) CCI rises then falls while CLK remains high.  CCIFG remains low.  When
  CLK falls CCIFG is set.
  */

  /* Advance the clock.  No action on rising edge. */
  last_outclk = outclk;
  HALF_TICK_OUTCLK();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, last_outclk+1);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_LOW();
  ASSERT_CLOCK_HIGH();

  /* Check that external triggers with sync async do not trigger when
   * clock does not advance. */
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_LOW();
  HALF_TRIGGER();
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_HIGH();
  HALF_TRIGGER();
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_LOW();

  /* Falling edge does not increment counter but does cause capture */
  last_outclk = outclk;
  HALF_TICK_OUTCLK();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, last_outclk);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  ASSERT_YES_CAPTURE();
  ASSERT_CCI_LOW();
  CLEAR_CAPTURE();

  /* Now test it with internal toggles.  First, asynchronous: */
  timer_hpl->cctl[APP_CCIDX] = CM_3 | CCIS_2 | SCCI | CAP;
  ASSERT_NO_CAPTURE();
  ASSERT_INTERNAL_TRIGGER_LOW();
  ASSERT_CCI_LOW();
  HALF_TRIGGER();
  ASSERT_CCI_LOW();
  ASSERT_NO_CAPTURE();
  INTERNAL_HALF_TRIGGER();
  ASSERT_CCI_HIGH();
  ASSERT_INTERNAL_TRIGGER_HIGH();
  ASSERT_YES_CAPTURE();
  CLEAR_CAPTURE();
  HALF_TRIGGER();
  ASSERT_CCI_HIGH();
  ASSERT_NO_CAPTURE();
  INTERNAL_HALF_TRIGGER();
  ASSERT_CCI_LOW();
  ASSERT_INTERNAL_TRIGGER_LOW();
  ASSERT_YES_CAPTURE();
  ASSERT_CCI_LOW();
  CLEAR_CAPTURE();

  /* Now synchronous */
  timer_hpl->cctl[APP_CCIDX] |= SCS;

  ASSERT_NO_CAPTURE();
  ASSERT_INTERNAL_TRIGGER_LOW();
  INTERNAL_HALF_TRIGGER();
  ASSERT_INTERNAL_TRIGGER_HIGH();
  ASSERT_NO_CAPTURE();
  INTERNAL_HALF_TRIGGER();
  ASSERT_INTERNAL_TRIGGER_LOW();
  ASSERT_NO_CAPTURE();

  /* Advance the clock.  No action on rising edge. */
  last_outclk = outclk;
  HALF_TICK_OUTCLK();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, last_outclk+1);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  ASSERT_NO_CAPTURE();
  ASSERT_CCI_LOW();
  ASSERT_CLOCK_HIGH();

  /* Falling edge does not increment counter but does cause capture */
  last_outclk = outclk;
  HALF_TICK_OUTCLK();
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, last_outclk);
  BSP430_UNITTEST_ASSERT_EQUAL_FMTx(outclk, timer_hpl->r);
  ASSERT_YES_CAPTURE();
  ASSERT_CCI_LOW();
  CLEAR_CAPTURE();

  cprintf("%u: Timer: R %04x CTL %04x CCR %04x CCTL %04x\n", __LINE__, timer_hpl->r, timer_hpl->ctl, timer_hpl->ccr[APP_CCIDX], timer_hpl->cctl[APP_CCIDX]);
  vBSP430unittestFinalize();
}
Beispiel #6
0
void main ()
{
  volatile sBSP430hplPORTIE * b0hpl;
  hBSP430halTIMER b0timer_hal;
  int b0pin = iBSP430portBitPosition(BSP430_PLATFORM_BUTTON0_PORT_BIT);
  struct sBSP430timerPulseCapture pulsecap_state;
  hBSP430timerPulseCapture pulsecap;
  unsigned long freq_Hz;
  int rc;

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();

  cprintf("\npulsecap " __DATE__ " " __TIME__ "\n");

  cprintf("There's supposed to be a button at %s.%u\n",
          xBSP430portName(BSP430_PLATFORM_BUTTON0_PORT_PERIPH_HANDLE),
          b0pin);
  b0hpl = xBSP430hplLookupPORTIE(BSP430_PLATFORM_BUTTON0_PORT_PERIPH_HANDLE);
  if (NULL == b0hpl) {
    cprintf("Guess it's not there.  Never mind.\n");
    return;
  }
  cprintf("Found it at %p.  Now looking for timer HAL.\n", b0hpl);
  b0timer_hal = hBSP430timerLookup(BUTTON0_TIMER_PERIPH_HANDLE);
  if (NULL == b0timer_hal) {
    cprintf("That's not there, though.  Going away now.\n");
    return;
  }
  vBSP430timerResetCounter_ni(b0timer_hal);
  b0timer_hal->hpl->ctl = TASSEL__SMCLK | MC__CONTINOUS | TBCLR | TBIE;
  vBSP430timerInferHints_ni(b0timer_hal);
  freq_Hz = ulBSP430timerFrequency_Hz_ni(BUTTON0_TIMER_PERIPH_HANDLE);

  cprintf("Cool, we're good to go with a %lu Hz timer at %p, now %lu.\n",
          freq_Hz, b0timer_hal, ulBSP430timerCounter_ni(b0timer_hal, NULL));

  /* Configure the port for its primary peripheral function */
  b0hpl->dir &= ~BSP430_PLATFORM_BUTTON0_PORT_BIT;
  BSP430_PORT_HPL_SET_REN(b0hpl, BSP430_PLATFORM_BUTTON0_PORT_BIT, BSP430_PORT_REN_PULL_UP);
  BSP430_PORT_HPL_SET_SEL(b0hpl, BSP430_PLATFORM_BUTTON0_PORT_BIT, 1);

  pulsecap = hBSP430timerPulseCaptureInitialize(&pulsecap_state,
                                                BUTTON0_TIMER_PERIPH_HANDLE,
                                                BUTTON0_TIMER_CCIDX,
                                                BUTTON0_TIMER_CCIS,
                                                BSP430_TIMER_PULSECAP_START_CALLBACK | BSP430_TIMER_PULSECAP_END_CALLBACK,
                                                pulsecap_callback_ni);
  if (NULL == pulsecap) {
    cprintf("Sorry, pulsecap initialization failed\n");
    return;
  }
  cprintf("%s.%u%c cctl %04x; pulsecap %p flags %04x\n",
          xBSP430timerName(BUTTON0_TIMER_PERIPH_HANDLE),
          BUTTON0_TIMER_CCIDX,
          'A' + (BUTTON0_TIMER_CCIS / CCIS0),
          b0timer_hal->hpl->cctl[BUTTON0_TIMER_CCIDX],
          pulsecap, pulsecap->flags_ni);

  /* Need to enable interrupts so timer overflow events are properly
   * acknowledged */
  BSP430_CORE_ENABLE_INTERRUPT();

  rc = iBSP430timerPulseCaptureEnable(pulsecap);
  cprintf("Enable got %d\n", rc);
  rc = iBSP430timerPulseCaptureActivate(pulsecap);
  cprintf("Activate got %d\n", rc);
  while (1) {
    unsigned int flags;
    unsigned long pulseWidth_tt;
    unsigned int overflows;
    unsigned int activehighs;

    BSP430_CORE_DISABLE_INTERRUPT();
    do {
      flags = pulsecap_state.flags_ni;
      pulseWidth_tt = pulseWidth_tt_v;
      overflows = overflows_v;
      activehighs = activehighs_v;
    } while (0);
    BSP430_CORE_ENABLE_INTERRUPT();
    cprintf("Timer %lu flags %04x ; %u over %u activehigh\n",
            ulBSP430timerCounter(b0timer_hal, NULL),
            flags, overflows, activehighs);
    if (0 != pulseWidth_tt) {
      cprintf("\tNew width: %lu ticks = %lu us\n", pulseWidth_tt,
              (unsigned long)((1000ULL * pulseWidth_tt) / (freq_Hz / 1000UL)));
      pulseWidth_tt = 0;
    }
    BSP430_CORE_DELAY_CYCLES(BSP430_CLOCK_NOMINAL_MCLK_HZ);
  }
}
Beispiel #7
0
void main ()
{
  int rc;
  sBSP430m25p m25p_data;
  hBSP430m25p m25p;
  unsigned long addr;
  unsigned long t0;
  unsigned long t1;

  vBSP430platformInitialize_ni();
  (void)iBSP430consoleInitialize();

  cprintf("\nBuild " __DATE__ " " __TIME__ "\n");
  cprintf("SPI is %s: %s\n",
          xBSP430serialName(BSP430_PLATFORM_M25P_SPI_PERIPH_HANDLE),
          xBSP430platformPeripheralHelp(BSP430_PLATFORM_M25P_SPI_PERIPH_HANDLE, 0));

#ifdef BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE
  cprintf("PWR at %s.%u\n",
          xBSP430portName(BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(BSP430_PLATFORM_M25P_PWR_PORT_BIT));
#else /* BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE */
  cprintf("PWR is hard-wired\n");
#endif /* BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE */

#ifdef BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE
  cprintf("RSTn at %s.%u\n",
          xBSP430portName(BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(BSP430_PLATFORM_M25P_RSTn_PORT_BIT));
#else /* BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE */
  cprintf("RSTn is hard-wired\n");
#endif /* BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE */
  cprintf("CSn at %s.%u\n",
          xBSP430portName(BSP430_PLATFORM_M25P_CSn_PORT_PERIPH_HANDLE),
          iBSP430portBitPosition(BSP430_PLATFORM_M25P_CSn_PORT_BIT));

  memset(&m25p_data, 0, sizeof(m25p_data));
  m25p_data.spi = hBSP430serialLookup(BSP430_PLATFORM_M25P_SPI_PERIPH_HANDLE);
  m25p_data.csn_port = xBSP430hplLookupPORT(BSP430_PLATFORM_M25P_CSn_PORT_PERIPH_HANDLE);
  m25p_data.csn_bit = BSP430_PLATFORM_M25P_CSn_PORT_BIT;
#ifdef BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE
  m25p_data.rstn_port = xBSP430hplLookupPORT(BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE);
  m25p_data.rstn_bit = BSP430_PLATFORM_M25P_RSTn_PORT_BIT;
#endif /* BSP430_PLATFORM_M25P_RSTn_PORT_PERIPH_HANDLE */

  m25p = hBSP430m25pInitialize(&m25p_data,
                               BSP430_SERIAL_ADJUST_CTL0_INITIALIZER(UCCKPL | UCMSB | UCMST),
                               UCSSEL_2, 1);
  if (NULL == m25p) {
    cprintf("M25P device initialization failed.\n");
    return;
  }

#ifdef BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE
  {
    volatile sBSP430hplPORT * pwr_hpl;
    /* Turn on power, then wait 10 ms for chip to stabilize before releasing RSTn. */
    pwr_hpl = xBSP430hplLookupPORT(BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE);
    pwr_hpl->out &= ~BSP430_PLATFORM_M25P_PWR_PORT_BIT;
    pwr_hpl->dir |= BSP430_PLATFORM_M25P_PWR_PORT_BIT;
    pwr_hpl->out |= BSP430_PLATFORM_M25P_PWR_PORT_BIT;
    BSP430_CORE_DELAY_CYCLES(10 * (BSP430_CLOCK_NOMINAL_MCLK_HZ / 1000));
  }
#endif /* BSP430_PLATFORM_M25P_PWR_PORT_PERIPH_HANDLE */
  BSP430_M25P_RESET_CLEAR(m25p);

  cprintf("Status register %d\n", iBSP430m25pStatus_ni(m25p));
  rc = iBSP430m25pStrobeCommand_ni(m25p, BSP430_M25P_CMD_WREN);
  cprintf("WREN got %d, status register %d\n", rc, iBSP430m25pStatus_ni(m25p));
  rc = iBSP430m25pStrobeCommand_ni(m25p, BSP430_M25P_CMD_WRDI);
  cprintf("WRDI got %d, status register %d\n", rc, iBSP430m25pStatus_ni(m25p));

  rc = iBSP430m25pInitiateCommand_ni(m25p, BSP430_M25P_CMD_RDID);
  if (0 == rc) {
    rc = iBSP430m25pCompleteTxRx_ni(m25p, NULL, 0, 20, buffer);
  }

  BSP430_CORE_ENABLE_INTERRUPT();
  cprintf("READ_IDENTIFICATION got %d\n", rc);
  if (0 <= rc) {
    dumpMemory(buffer, rc, 0);
  }
  cprintf("Config identified %u sectors of %lu bytes each: %lu bytes total\n",
          BSP430_PLATFORM_M25P_SECTOR_COUNT,
          (unsigned long)BSP430_PLATFORM_M25P_SECTOR_SIZE,
          BSP430_PLATFORM_M25P_SECTOR_COUNT * (unsigned long)BSP430_PLATFORM_M25P_SECTOR_SIZE);
#if (BSP430_PLATFORM_M25P_SUBSECTOR_SIZE - 0)
  cprintf("Config supports access as %u sub-sectors of %u bytes each\n",
          (unsigned int)(BSP430_PLATFORM_M25P_SECTOR_COUNT * (BSP430_PLATFORM_M25P_SECTOR_SIZE / BSP430_PLATFORM_M25P_SUBSECTOR_SIZE)),
          (unsigned int)BSP430_PLATFORM_M25P_SUBSECTOR_SIZE);
#else /* BSP430_PLATFORM_M25P_SUBSECTOR_SIZE */
  cprintf("Config indicates device is not sub-sector addressable\n");
#endif /* BSP430_PLATFORM_M25P_SUBSECTOR_SIZE */
  cprintf("RDID identified %lu bytes total capacity\n", 0x1UL << buffer[2]);

  addr = 0;

  rc = readFromAddress(m25p, addr, sizeof(flashContents));
  if (sizeof(flashContents) != rc) {
    cprintf("ERROR %d reading initial block\n", rc);
  } else {
    dumpMemory(buffer, rc, addr);
    if (0 == memcmp(flashContents, buffer, rc)) {
      cprintf("Found expected contents.\n");
    }
  }

#if (BSP430_PLATFORM_M25P_SUPPORTS_PE - 0)
  rc = writeToAddress(m25p, BSP430_M25P_CMD_PE, addr, NULL, 0);
  cprintf("PAGE_ERASE got %d\n", rc);
#else /* BSP430_PLATFORM_M25P_SUPPORTS_PE */
  rc = writeToAddress(m25p, BSP430_M25P_CMD_SE, addr, NULL, 0);
  cprintf("SECTOR_ERASE got %d\n", rc);
#endif /* BSP430_PLATFORM_M25P_SUPPORTS_PE */
  rc = readFromAddress(m25p, addr, sizeof(buffer));
  if (0 < rc) {
    dumpMemory(buffer, rc, addr);
  }

  rc = writeToAddress(m25p, BSP430_M25P_CMD_PP, addr, flashContents, sizeof(flashContents));
  cprintf("PAGE_PROGRAM got %d\n", rc);
  rc = readFromAddress(m25p, addr, sizeof(buffer));
  if (0 < rc) {
    dumpMemory(buffer, rc, addr);
  }

  /* PAGE PROGRAM is the one that only clears 1s to 0s so needs a
   * prior page or sector erase */
  rc = writeToAddress(m25p, BSP430_M25P_CMD_PP, addr, flashContents + 4, 4);
  cprintf("PAGE_PROGRAM to %lx returned %d\n", addr, rc);
  rc = readFromAddress(m25p, 0, sizeof(flashContents));
  dumpMemory(buffer, rc, 0);
  /*
  Write 4 took 8
  PAGE_PROGRAM to 0 returned 4
  00000000  88 11 03 30 cc 33 c3 3c  01 23 45 67 89 ab cd ef  ...0.3.<.#Eg....
  */

  /* PAGE_WRITE is the one that does not need a prior erase cycle */
  addr = 8;
#if (BSP430_PLATFORM_M25P_SUPPORTS_PW - 0)
  rc = writeToAddress(m25p, BSP430_M25P_CMD_PW, addr, flashContents + 4, 4);
  cprintf("PAGE_WRITE to %lx returned %d\n", addr, rc);
#else
  rc = writeToAddress(m25p, BSP430_M25P_CMD_PP, addr, flashContents + 4, 4);
  cprintf("overwrite PAGE_PROGRAM to unerased %lx returned %d\n", addr, rc);
#endif
  rc = readFromAddress(m25p, 0, sizeof(flashContents));
  dumpMemory(buffer, rc, 0);
  /*
  Write 4 took 204
  PAGE_WRITE to 8 returned 4
  00000000  88 11 03 30 cc 33 c3 3c  cc 33 c3 3c 89 ab cd ef  ...0.3.<.3.<....
  */

  cprintf("Initiating bulk erase...");
  BSP430_CORE_DISABLE_INTERRUPT();
  do {
    t0 = t1 = 0;
    rc = iBSP430m25pStrobeCommand_ni(m25p, BSP430_M25P_CMD_WREN);
    if (0 == rc) {
      rc = iBSP430m25pStrobeCommand_ni(m25p, BSP430_M25P_CMD_BE);
    }
    if (0 == rc) {
      int sr;

      t0 = ulBSP430uptime_ni();
      do {
        sr = iBSP430m25pStatus_ni(m25p);
      } while ((0 <= sr) && (BSP430_M25P_SR_WIP & sr));
      t1 = ulBSP430uptime();
    }
  } while (0);
  BSP430_CORE_ENABLE_INTERRUPT();
  cprintf("\nBULK_ERASE got %d\n", rc);
  if (0 == rc) {
    char tstr[BSP430_UPTIME_AS_TEXT_LENGTH];
    cprintf("Bulk erase took %lu utt = %s\n", t1-t0, xBSP430uptimeAsText(t1 - t0, tstr));
  }
  rc = readFromAddress(m25p, 0, sizeof(flashContents));
  dumpMemory(buffer, rc, 0);

  rc = writeToAddress(m25p, BSP430_M25P_CMD_PP, 0, flashContents, sizeof(flashContents));
  cprintf("Restore got %d\n", rc);

  addr = 0;
  while (addr < (256 * 1025L)) {
    rc = readFromAddress(m25p, addr, sizeof(buffer));
    if (0 > rc) {
      break;
    }
    dumpMemory(buffer, rc, addr);
    addr += rc;
    break;
  }

}