Go Down

Topic: how to use Due PB0-PB7 pins as an external interrupt (Read 1 time) previous topic - next topic

t_bostanjyan

In my board I need to use PB0-PB7 ports as an external interrupt sources.

Is it possible?

I spent a lot of time to understand that. Seems the easiest way is to update variant.cpp file by adding these pins.

Unfortunately this is not the solution I'm looking for (actually this can be a solution if I'm able to add pins from the sketch, but it is not possible to update cons dynamic array after declaration ).

Another way is to create my own interrupt handler. But I didn't find how should I do that.


t_bostanjyan

Common guys.
Really nobody knows?

Can I use PB0-PB7 as an external interrupt sources?


george4657

i may be wrong but looking at the due board and schematic.
Pins PB0 to PB are ethernet pins and not connected to any connector.
You would have to connect to the pins of the ATSAM3X8E chip.
You can check the datasheet to see if these pins are able to be used as port pins if you can figure a way to connect to them.
 

t_bostanjyan

I designed my own due compatible board.
According to the ATSAM3X8E it is possible to use these pins as a GPIO.
But the issue is that they are not included in the Arduino Due environment. That's why I can not use usual attachInterrupt function.

westfw


Quote
Seems the easiest way is to update variant.cpp file by adding these pins.
Unfortunately this is not the solution I'm looking for
Why not?  It looks like pretty much all of the code to handle the PB0..7 interrupts is already there, EXCEPT for the code that maps Arduino "pins" to internal info like Port and bit.  Since PIOB is 32bits wide, and other bits of the port ARE in use, the PIOB interrupt handler is already in use, so you can't just define your own handler.

If you're really intent on not defining "pins", it looks like you could tie into the low-level WInterrupt.c structure:
Code: [Select]

void PIOB_Handler(void) {
uint32_t isr = PIOB->PIO_ISR;
uint32_t i;
for (i=0; i<32; i++, isr>>=1) {
if ((isr & 0x1) == 0)
continue;
if (callbacksPioB[i])
callbacksPioB[i]();
}
}

While attachInterrupt() needs "pins" defined, it looks like you could modify callbacksPioB[] directly, a sort of "attach interrupt to PB0..7 without knowing (or needing to know) whether or not they are "pins."

Speklap

Hi

I'm trying something similar. I have a switch connected to pin 13, aka PB27.

I enabled the interrupt.
Code: [Select]

  NVIC_EnableIRQ(PIOB_IRQn);

  PIOB -> PIO_PER |= PIO_PER_P27;
  PIOB -> PIO_IER |= PIO_IER_P27;
  PIOB -> PIO_ESR |= PIO_ESR_P27;
  PIOB -> PIO_FELLSR |= PIO_FELLSR_P27;


with this interrupt function:
Code: [Select]

void PIOB_Handler() {

  if (PIOB -> PIO_ISR & PIO_ISR_P27) {

    Serial.println("event occured");
    // do something

  }

}



I only include "Arduino.h" at the beginning of the file.

When compiling:
Quote
C:\Users\ABC\Desktop\arduino_sketches\test_adc>platformio run
[05/14/18 12:36:33] Processing due (platform: atmelsam; board: due; framework: a
rduino)
-------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
PLATFORM: Atmel SAM > Arduino Due (Programming Port)
SYSTEM: AT91SAM3X8E 84MHz 32KB RAM (512KB Flash)
DEBUG: CURRENT(blackmagic) EXTERNAL(blackmagic, jlink)
Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF MODES: FINDER(chain) COMPATIBILITY(light)
Collected 3 compatible libraries
Scanning dependencies...
No dependencies
Linking .pioenvs\due\firmware.elf
.pioenvs\due\libFrameworkArduino.a(WInterrupts.c.o): In function `PIOB_Handler':

WInterrupts.c:(.text.PIOB_Handler+0x0): multiple definition of `PIOB_Handler'
.pioenvs\due\src\due_adc.cpp.o:due_adc.cpp:(.text.PIOB_Handler+0x0): first defin
ed here
collect2.exe: error: ld returned 1 exit status
*** [.pioenvs\due\firmware.elf] Error 1
I googled this, and found that it was due to including arduino.h. When exluding arduino.h and including sam.h it doesnt show the error, but now Serial doesn't get recognized.

How can I fix it?

Thanks

ard_newbie


Can't you use attachinterrupt() with arduino pin 13 (PB27)? It works if you previously power PIOB with pinMode(13, INPUT) or pinMode(13, OUTPUT).

Winterrupts.c does the job for you by programming a call back function.

Speklap

Because I'd like to use "hardware specific code" (if that makes sense), than "Arduino code". Arduino code doesn't give much insight in the hardware and their registers. I think it will help me further in the future if I start to use other boards so the principe stays the same.

I'm also not using the Arduino IDE. It's sublime text and platformio. I say this cause when googling some of the topics refer to the IDE.


Code: [Select]

void test_Handler() {

  Serial.println("test");

  if (PIOB -> PIO_ISR & PIO_ISR_P27) {

    Serial.println("event occured");
    adc_setup();
    tc_setup();

  }

}

void setup() {

  NVIC_EnableIRQ(PIOB_IRQn);

  /*PIOB -> PIO_PER |= PIO_PER_P27;
  PIOB -> PIO_IER |= PIO_IER_P27;
  PIOB -> PIO_ESR |= PIO_ESR_P27;
  PIOB -> PIO_FELLSR |= PIO_FELLSR_P27;*/

  PIOD -> PIO_OER = (1ul << 8);

  PIOD -> PIO_SODR = 1ul << 8;

  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST77XX_BLACK);

  tftPrint(0);

  pinMode(13, INPUT);
  attachInterrupt(13, test_Handler, FALLING);

  // adc_setup();
  // tc_setup();

  PIOD -> PIO_CODR = 1ul << 8;
  PIOD -> PIO_SODR = 1ul << 8;
  PIOD -> PIO_CODR = 1ul << 8;
  PIOD -> PIO_SODR = 1ul << 8;
  PIOD -> PIO_CODR = 1ul << 8;


}



test_Handler never gets executed.

Ultimately, I'll use flags to execute the code in the handler in setup or loop. Test_handler should be only called once when switching the switch to start the program. After that it should keep running


EDIT: so changing/commenting out in Winterrupts.c/h can fix this error?

ard_newbie


I never tried to suppress Winterrupts.c, but if you would do that, I guess you could program PIOA_Handler(), PIOB_Handler(), PIOC_Handler() and PIOD_Handler() by yourself.  Read the code in Winterrupts.c, it is interesting.

Speklap

https://github.com/arduino/ArduinoCore-sam/blob/master/cores/arduino/WInterrupts.c

was indeed interesting, looks like I forgot setting in AIMER register, "pio->PIO_AIMER = mask;"

But I can't seem to find this file on my windows system.
 Windows points only to this dir: C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino and WInterrupts.c is different than the one on github.


My code in post #7. Does it looks correct? Even that doesn't work

ard_newbie

#10
May 14, 2018, 04:12 pm Last Edit: May 14, 2018, 04:23 pm by ard_newbie
An example sketch with attachinterrupt(), the call back function detects a Rising edge of TIOA0 pulse from Timer Counter 0 Channel 0:



Code: [Select]

/*******************************************************************/
/*                Hook a jumper between pin 24 and pin 2           */
/*******************************************************************/  

void ISR1() {

    PIOB->PIO_ODSR ^= PIO_ODSR_P27;   // Toggle LED with a 1 Hz frequency
}

void setup() {
  pinMode(24, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  

  /*************  Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0  ************/
  PMC->PMC_PCER0 |= PMC_PCER0_PID27;                      // TC0 power ON - Timer Counter 0 channel 0 IS TC0

  PIOB->PIO_PDR |= PIO_PDR_P25;
  PIOB->PIO_ABSR |= PIO_ABSR_P25;

  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK4  // MCK/128, clk on rising edge
                              | TC_CMR_WAVE               // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA0 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA0 on RC compare match

  TC0->TC_CHANNEL[0].TC_RC = 656250;  //<*********************  Frequency = (Mck/128)/TC_RC  Hz
  TC0->TC_CHANNEL[0].TC_RA = 300000;  //<********************   Duty cycle = (TC_RA/TC_RC) * 100  %

  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC0 counter and enable

  attachInterrupt(24, ISR1, RISING);
}


void loop() {

}

Speklap

#11
May 14, 2018, 05:43 pm Last Edit: May 14, 2018, 05:44 pm by Speklap
It works now with the attachinterrupt. I don't know what I did different this time. Thanks

Code: [Select]

volatile uint8_t flag_startup;

void ISR1() {

    flag_startup = 1;

}

void setup_enbl() {

pinMode(13, INPUT);
attachInterrupt(13, ISR1, RISING);

}


void setup() {

flag_startup = 0;

flag_freq_lagging = 0;

init_output();

setup_adc_timer();
enable_adc_timer();

setup_lag_timer();
enable_lag_timer();

setup_pwm_timers();
setup_freq_timer();
setup_adc();

setup_enbl();

while (flag_startup == 0) {}

flag_startup = 0;

while (flag_startup == 0) {}

flag_startup = 0;

enable_adc();
enable_pwm_timers();
enable_freq_timer();

tft.initR(INITR_BLACKTAB);
tft.fillScreen(ST77XX_BLACK);
tftPrint();

}




With the external hw switch, it bounces. It gets immediately executed. So for now I just wait until it rises 2 times. Next time my pcb shield will be finished so I can test it further without to much noise from breadboard/cables/.. Might also test some stuff out with the debounce filter and input glitch.

Go Up