arduino / arduino/ArduinoCore-samd

SAMD and/or Arduino problems when analogWrite() digitalWrite() and servo library are combined

Open
#176 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
502
Forks
740
PR merge metrics
No merged PRs in 30d

Description

Hi folks!,

This is my first issue in GitHub so please, excuse my mistakes / misunderstandings.

I've been investigating trying to solve problems I have in my Feather M0 SAMD board when diferent types of functionallity are being mixed.

After a long time, I have not been able to understand why so, as a Adafruit customer, I have been in contact with the technical support and a "small" example ;-) has been created.
As Adafruit said me, I'm going to share my problem because maybe one or more Arduino/Atmel bugs and/or incompatibilities has been located.

I post here a reduced sketch for somebody who wants to be able to reproduce the symptoms by trying to share my headaches with this team and to contribute to make Arduino development better, sorry for that.

Any help will be welcomed.

_NOTE: Example is self descriptive so, read the comments_
_See [https://forums.adafruit.com/viewtopic.php?f=57&t=104955](url) for further information_

`//
// Author: Julián Rodríguez (Oct.2016)
//
// A) Example to show the problem with Arduino (or HW) when used same pin as output
// to generate Digital and Analog (PWM) data sequentially and after a time.
// B) Aditional problem found is when 15 (A1) pin is used as analogWrite (PWM) and servo library
// attached() is invoked over other pin (for example 5 in my case). The first one (A1) then,
// stops the PWM train pulses generation.
//
// The conclusion is:
// A) When a pin is changed to produce PWM (analogWrite()), will never can be used
// again to generate DIG output (digitalWrite()). It's neccesary to restart the
// sketch from the begining by resetting program.
//
// B) Don't know why, investigation should be neccesary but, maybe that shared timers/counters
// are being used and the performance of SAMD are degraded.
//
// NOTE: delay function is not being used to avoid the possibility to use shared timers

//If both of next lines are disabled, no problem is selected. The sketch is going to executed
// doing changes over output pin as DIGITAL (HIGH / LOW) changes periodically

//#define SHOW_ANADIG_PROBLEM //Uncomment to enable the functional mode to show ANADIG problem
//#define SHOW_ANASERVO_PROBLEM //Uncomment to enable the functional mode to show ANASERVO problem
# if defined(SHOW_ANADIG_PROBLEM) && defined(SHOW_ANASERVO_PROBLEM)

#error "Both problems at same time are not allowed!. ONLY one #define line must be enabled for the problem to be checked."
# endif
# ifdef SHOW_ANASERVO_PROBLEM

#include
Servo MyServo;
#define SERVO 6 //Pin that is going to be assigned to control a servo
#define SERVO_POS_MIN 800 //Min (CCW) Position
#define SERVO_POS_NOM 1500 // Initial Position
#define SERVO_POS_MAX 2200 //Max ( CW) Position
# endif
# define PinToBeChecked A1 // Te pin to be tested (13 if board led is used), A1 if AIN1(15) used, and so on...

unsigned long Wait_uS = 3825000; // Time duration to work in each mode (DIG / ANA) to make cycling
unsigned long Start_uS;
byte data = 0;
byte loops= 0;

//
// Following definitions are applied during the time duration of the mode selected (always during the period of Wait_uS)
//
# define Width_ON_ms 5 //How much ms we need to mantain an ON state (for ANA, PWM changes only in this time). for DIG

```
// mode, the level will be HIGH all this time.
```
# define Width_OFF_ms 10 //and ... how much we are going to delay at OFF to repeat a new PRF

//
//Following pin definition could be the same in both cases if the pin is going to be changed from
//DIG to ANA mode. Otherwise, could be different.
//
int ANA = PinToBeChecked; //Pin used for ANA (output is PWM)
int DIG = PinToBeChecked; //Pin used for DIG (output is HIGH/LOW)

void DoWait_mS(unsigned long mS)
{
unsigned long currentMillis;
unsigned long previousMillis;

currentMillis = millis();
previousMillis = currentMillis;

while ( (currentMillis - previousMillis) < mS)
{
currentMillis = millis();
//Do other task
}
}

void Print_Results()
{
Serial.print(" Number of Loops (255 steps)= "); Serial.print(loops);
Serial.print(" plus aditional "); Serial.print(data);
Serial.print(" steps (total= "); Serial.print( (loops \* 255) + data);
Serial.print(" changes in "); Serial.print( Wait_uS ); Serial.println(" uS)");
}

void Do_ANA() //Generate changes cycling in PWM (during Width_ON_ms time only) each Wait_uS period time
{
Start_uS = micros();
data = 0;
loops = 0;
while ( ( micros() - Start_uS ) < Wait_uS )
{
pinMode(ANA, OUTPUT); // make sure to do it over and over again
data++;
if (data == 255)
loops++;

```
analogWrite(ANA, data);
DoWait_mS(Width_ON_ms);

analogWrite(ANA, 0);
DoWait_mS(Width_OFF_ms);
```

}
Print_Results();
}

void Do_DIG() //Generate changes cycling in levels (during Width_ON_ms will be HIGH) each Wait_uS period time
{
Start_uS = micros();
data = 0;
loops = 0;
while ( ( micros() - Start_uS ) < Wait_uS )
{
pinMode(DIG, OUTPUT); // make sure to do it over and over again
data++;
if (data == 255)
loops++;

```
digitalWrite(DIG, data/2);
DoWait_mS(Width_ON_ms);

digitalWrite(DIG, 0);
DoWait_mS(Width_OFF_ms);
```

}
Print_Results();
}

void setup()
{
Serial.begin(115200);
while (Serial.available());
DoWait_mS(1000);
Serial.println("\n\rTesting ANALOG / DIGITAL Behaviour. [JRV]");
Serial.println("=========================================\n\r");
# ifdef SHOW_ANADIG_PROBLEM

Serial.println(" [Showing the ANADIG behaviour when using analogWrite() after use of digitalWrite() in the same pin]\n\r");
# elif defined SHOW_ANASERVO_PROBLEM

Serial.println(" [Showing the ANASERVO behaviour when using attach() in pin 5 after use of analogWrite() in the A1 pin]\n\r");
# else

Serial.println(" [No problem to show. It works only as DIG mode with digitalWrite() over the A1 pin]\n\r");
# endif

}

void loop()
{
Serial.println();
# if defined (SHOW_ANADIG_PROBLEM)

Serial.println("Configuring data for DIGITAL mode (pin A1) and cycling pin status");
Do_DIG();
Serial.println("Configuring data for ANALOG (PWM) mode and cycling pin status. Changes in A1 pin as digital are ONLY done before analogWrite");
Do_ANA();
# elif defined (SHOW_ANASERVO_PROBLEM)

Serial.println("Configuring data for ANALOG (PWM) mode and cycling pin status. Changes in A1 pin are ONLY done before servo attach");

Do_ANA();

MyServo.attach(SERVO);
MyServo.write(SERVO_POS_MIN);
DoWait_mS(500);
MyServo.write(SERVO_POS_MAX);
DoWait_mS(500);
MyServo.write(SERVO_POS_NOM);
DoWait_mS(500);
# else //No problem to be reproduced so, only use digital output change with digitalWrite()

Serial.println("Configuring data for DIGITAL mode (pin A1) and cycling pin status");
Do_DIG();
# endif

}
`

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by running the reduced sketch from the issue on the Feather M0, testing the SHOW_ANADIG_PROBLEM and SHOW_ANASERVO_PROBLEM cases separately. Read the analogWrite(), digitalWrite(), and Servo.attach() paths used by ArduinoCore-samd and compare their timer and pin behavior. Done means the reported interactions are explained and the affected behavior is corrected or documented with reproducible verification.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.