SPI and ICR1 problems


ive been working small project control 10x20 led matrix arduino. chose use 4 74hc595 shifters controlled spi. working well, , able draw images/text on display without issue.

i decided include hc-sr04 mix, display respond proximity, when problems started. have been unable both spi , hc-sr04 working together, can either working independently. is, when in same program way display stop  being updated during scan of hc-sr04. causes flickering effect on led matrix, undesirable.

the initial attempts of integration used arduino pulsein method, times (in microseconds) time signal goes high when goes low. problem implemented in libraries blocking call, meaning program unable update led matrix during pulse. instead, after looking @ atmega386p documentation, realised there icr1/icp1 functionality allow hardware time pulse width. below code shows attempt @ utilising icr1 time pulse:

code: [select]

/*
 * below code designed mimic arduino pulsein function,
 * using icr mechanism of timer1 interrupts instead of
 * software implementation. means work on
 * portb, pin0 of atmega328p, i.e. arduino pin 8.
 *
 * below developed wait rising edge on be
 * detected icr, start timer 1 prescaler 8, wait for
 * falling edge , save value of timer icr1.
 */


/*
  these variables used within isr pulse
  detection track state.
 */
volatile bool icr_pulse_done = false;
volatile bool icr_pulse_error = false;
volatile uint16_t icr_pulse_value = 0;

void icr_pulse_enable(void) {
  /* initilise state tracking variables */
  icr_pulse_error = false;
  icr_pulse_done = false;
  /* configure timer1 in normal mode */
  tccr1a = 0;
  /* configure icr on rising edge noise filter */
  tccr1b = _bv(ices1) | _bv(icnc1);
  /* unmask icr */
  timsk1 = _bv(icie1);
}

/*
 * called when timer1 overflows, i.e. times out looking event
 */
isr(timer1_ovf_vect) {
  /* stop timer1 */
  tccr1b = 0;
  /* mask timer1 interrupts */
  timsk1 = 0;
  /* mark error status */
  icr_pulse_error = true;
}

/*
 * called when edge change detected timer1, can
 * called without timer1 being started.
 */
isr(timer1_capt_vect) {
  if (tccr1b & _bv(ices1)) {
    /* looking edge */

    /* clear timer 1 counter */
    tcnt1 = 0;
    /* enable interrupt overflow */
    timsk1 |= _bv(toie1);
    /* start timer 1 prescaler or 8 */
    tccr1b = _bv(cs11) | _bv(icnc1);
  } else {
    /* looking down edge */

    /* stop timer1 */
    tccr1b = 0;
    /* mask timer1 interrupts */
    timsk1 = 0;
    /* make cycle complete */
    icr_pulse_done = true;
    /* divide icr1 2 convert microseconds */
    icr_pulse_value = icr1 / (f_cpu/1000000/8);
  }
}


the below code sample arduino program code utilise above code trigger pulse on hc-sr04 every 100 milliseconds, , write dummy data on spi:
code: [select]

/*
 * portb
 *  pin5 |-> pin13 (sck)
 *  pin3 |-> pin11 (mosi)
 *  pin2 |-> pin10 (output/ss)
 *  pin0 |-> pin8 (icp1, external 10k pulldown)
 *
 * portd
 *  pin7 |-> pin7 (output, low enable outputs on sn74ch595)
 *  pin6 |-> pin6 (output, trigger hc-sr04)
 *
 * connected to: sn74hc595
 *  arduino pin13 (sck) connected sn74hc595 pin11 (srclk)
 *  arduino pin11 (mosi) connected sn74hc595 pin14 (ser)
 *  arduino pin10 connected sn74hc595 pin12 (rclk)
 *  arduino pin7 connected sn74hc595 pin13 (oe)
 *  sn74hc595 pin10 high
 *
 * connected to: hc-sr04
 *  arduino pin6 (output) hc-sr04 trigger
 *  arduino pin8 (icp1) hc-sr04 echo
 */
#define pin_trigger   6
#define pin_echo      8
#define pin_ss        10
#define pin_oe        7

void setup() {
  serial.begin(9600);
  serial.println("hello world");

  /* set mosi, sck , ss output, others input */
  ddrb |= _bv(ddb3) | _bv(ddb5) | _bv(ddb2);
  /* enable spi, master, set clock rate fck/16 */
  spcr = _bv(spe) | _bv(mstr) | _bv(spr0);
  /* set trigger pin , output enable output */
  ddrd |= _bv(ddd6) | _bv(ddd7);
  /* set pin7 low */
  portd &= ~_bv(portd7);
}

/*
 * writes byte spi documented in atmega328p manual.
 */
void sendspi(uint8_t i_data) {
  digitalwrite(pin_ss,low);
  /* transmit high byte */
  spdr = i_data;
  /* wait transmission complete */
  while(!(spsr & (1<<spif)))
    ;
  digitalwrite(pin_ss,high);
  _delay_us(10);
}

uint32_t next_time_scan = 0;

void loop() {
  uint32_t = millis();

  /* send echo pulse */
  if (now >= next_time_scan) {
    /* send pulse every 100 milliseconds */
    next_time_scan += 100;
    /* enable icr interrupt, looking rising edge */
    icr_pulse_enable();
    /* set trigger on hc-sr04 high 10 microseconds */
    digitalwrite(pin_trigger,high);
    _delay_us(10);
    digitalwrite(pin_trigger,low);
  }

  /* if pulse detection complete, print depth in cm */
  if (icr_pulse_done) {
    uint16_t cm = icr_pulse_value/58;
    serial.print("depth: ");
    serial.println(cm);
    icr_pulse_done = false;
  }

  /* in case of timer1 overflow, print error , reset */
  if (icr_pulse_error) {
    serial.println("error");
    icr_pulse_error = false;
  }

  /*
   * line causes problems:
   *   sendspi(((uint8_t*)&now)[0]);
   * appears data sent on spi keeps changing
   * causes issues icr1.
   *
   * if replaced constant value, or 1 not change
   * issue resolved. e.g. both of following lines
   * ok.
   *   sendspi(((uint8_t*)&now)[1]);
   */
  sendspi(((uint8_t*)&now)[0]);
}


the problem above code depending on value written on spi, can effect value read icr1. example, if value written spi constant, or changes less every few milliseconds (> 250) ok, , pulse width detected correctly. however, if value changes @ high frequency value obtained icr1 incorrect.

for example, below output when last line sendspi(((uint8_t*)&now)[0]), i.e. lower byte of milliseconds since power on:
code: [select]

depth: 63
depth: 58
depth: 63
depth: 63
depth: 46
depth: 63
depth: 63
depth: 63
depth: 63

but without moving hardware, , reprogramming changing last line sendspi(((uint8_t*)&now)[1]) output is:
code: [select]

depth: 192
depth: 191
depth: 192
depth: 191
depth: 192
depth: 192
depth: 191

which correct measurement. byte changes every 256 milliseconds.


i have tried looking in atmega328p documentation can not see obvious reason use of spi should change value of icr1. both connected on portb, different pins, moreover, spi clock generator appears separate logical block on processor timer/counter1.

interestingly, have noticed if of spi pins (13, 11, 10) disconnected 74hc595 issue removed, , pulse width detected correctly. 74hc595 feeding interference?

"interestingly, have noticed if of spi pins (13, 11, 10) disconnected the 74hc595 then issue removed, , pulse width detected correctly. the 74hc595 is feeding interference? "

doubtful. '328p has 40ma drive capability, 74hc595's 1ua inputs not affect those.
and if had '595 outputs connected spi outputs, result in output drive transistors fighting each other, no logic impact rest of '328 functions.

you don't need delay in function
void sendspi(uint8_t i_data) {
the shift registers set after 8 srclk clocks , rclk going low high move data output latches.
do have 0.1uf cap each shift register vcc pin gnd? (and not on control line)

what speed using serial.begin()? 115200 or slow 9600? i'd go faster.







Arduino Forum > Using Arduino > LEDs and Multiplexing > SPI and ICR1 problems


arduino

Comments

Popular posts from this blog

Flip address is out of range arduino uno r3

Arduino Uno not uploading

Indesign and MathType fonts