Comments (11)
A little more testing shows that this code works fine:
uint16_t ledPin = 2;
void setup()
{
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
}
void loop()
{
for(uint16_t i = 1; i < 256; i++)
{
analogWrite(ledPin, i);
delay(10);
}
for(uint16_t j = 255; j > 0; j--)
{
analogWrite(ledPin, j);
delay(10);
}
}
However if I uncomment digitalWrite(ledPin, HIGH);
it won't count up the first time.
If I change the initial value in the first for loop to uint16_t i = 0;
, it won't count up at all.
It seems like this is related to when analogWrite(ledPin, 0)
is executed, which actually is just digitalWrite(ledPin, LOW)
from atmega328pb-testing.
I had a short look on the functions, but I also see no problem.
The timers are initialized in init() from wiring.c and the OC outputs are activated with analogWrite().
A digitalWrite(pin,val) will deactivate the OC output, because turnOffPWM(pin) is executed.
from atmega328pb-testing.
I suspect there might be a bug in the new and experimental toolchain (1.6.200).
I'm not able to print numbers using Serial.println. You can read my post about it here: arduino/Arduino#6899.
Too bad the 328PB isn't supported by the older toolchain (1.6.20).
from atmega328pb-testing.
There seems to be a hardware bug on timer 3+4 and the port register has to be written to 1 in order to get the output compare working: http://www.avrfreaks.net/comment/1717946#comment-1717946
So if you run analogWrite(ledPin, 0)
then the output compare (pwm) is deactivated on.
I have also tested the serial number printing and it is working with 1.6.200 for me.
from atmega328pb-testing.
OK. Seems like a workaround is necessary in order to get PWM pin pin 2 working properly. I think the fix below should be OK. I only own one ATmega328PB chip, with date code 1550. Do you know if this silicon error have been fixed in newer chips?
#if defined(TCCR3A) && defined(COM3B1)
case TIMER3B:
// connect pwm to pin on timer 3, channel B
PORTD |= _BV(PD2);
sbi(TCCR3A, COM3B1);
OCR3B = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case TIMER4B:
// connect pwm to pin on timer 4, channel B
PORTD |= _BV(PD2);
sbi(TCCR4A, COM4B1);
OCR4B = val; // set pwm duty
break;
#endif
from atmega328pb-testing.
I have tested it with one of our boards and I have to check the date code, but I think it is newer. In the datasheet (errata) is also nothing about it.
I would suggest to apply the workaround only for the 328PB and to use the sbi() macro:
#if defined(__AVR_ATmega328PB__)
sbi(PORTD, PD2);
#endif
from atmega328pb-testing.
Why use the sbi macro? It generates the same assembly code as "regular" bitwise operations. As far as I know the earlier version of the gcc tool chain wasn't properly optimized for the AVR architecture, and didn't "understood" that bitwise operations could be converted into sbi and cbi instructions.
Here's an avrfreaks thread about the topic: http://www.avrfreaks.net/forum/sbi-cbi
In fact the deprecated.h contains:
#define sbi(port, bit) (port) |= (1 << (bit))
and
#define cbi(port, bit) (port) &= ~(1 << (bit))
It no longer needs to use inline asm() as it knows that |= and &=~ will invoke usage of SBI and CLI
from atmega328pb-testing.
Because it is used in the Arduino source code and the chance that a pull-request is accepted is better, when the coding style/formatting is the same.
from atmega328pb-testing.
Well, good point..
from atmega328pb-testing.
The date code of my mega328PB where the issue also exists is 1619.
from atmega328pb-testing.
I have had the same issue but solved it and have the explanation. The fix is trivial, finding it took three days.
Summary
The "output compare modulator" is used when either output compare OC3B
or OC4B
or both is enabled. The way the datasheet describes it suggests the modulator is enabled only when both are enabled. The fix is trivial: set PD2
to 1 to select the "OR" function of the modulator's multiplexer.
There is a line in the datasheet which says this, but it's actually pretty well hidden and I didn't find it until writing this note. Even if you noticed the section on Output Modulation, you might not have read it in detail if you weren't intending to use it. There is no bug except in the documentation.
Explanation
Timer 3 and Timer 4 each has two output compare registers, A and B. OC3A
and OC4A
have their own pins 30 and 31 respectively, shared with PD0
and PD1
. OC3B
and OC4B
outputs share the same pin, 32, also with PD2
.
Enabling the output comparison pins is done with the COM3B
and COM4B
bits. If you enable both of them, this makes two (internal) signals OC3B
and OC4B
, controlled by the Waveform Generation Mode bits WGM3
and WGM4
. The output on pin 32 is the modulation of the two, chosen as 0C3B & OC4B
when PD2
is 0, OC3B | OC4B
when PD2
is 1.
The obvious way to get, say, simple PWM from OC3B
on pin 32 is to set WGM3
=14 (fast PWM noninverting), COM3B
= 2 (clear output on match, set on 0), DDRD2
=1 (output), and OC4B
=0 because it's not in use.
This is the surpise: It appears that when COM4B
=0, signal OC4B
is effectively zero, but the modulator is still in effect. Thus to get the desired OC3B
on pin 32, the "OR" function must be selected.by setting PD2
to 1. The same is true with COM4B
=0, to get OC3B
on pin 32, set PD2
to 1.
References: ATMega328PB datasheet DS40001906 rev C Feb 2018.
See figure 22.2, p247. What I've called OC3B
and OCR4B
are the outputs of their respective AND gates inside the grey boxes TC3 and TC4. Notice the only path for these two signals towards the output buffer is through the modulator.
The following is the description given at Section 22.2 for the modulator with my edits of what I believe it should say.
The Output Compare unit 3B and Output Compare unit 4B shares the PD2 port pin for output. The
outputs of the Output Compare units (OC3B and OC4B) overrides the normal PORTD2 Register when
one of them is enabled (that is, when COMnx[1:0] is not equal to zero). When either or both OC3B and OC4B are
enabledat the same time, it will also enable this modulator.
The functional equivalent schematic of the modulator is shown in the figure below. The schematic
includes part of the Timer/Counter units and the port D pin 2 output driver circuit. When the modulator is
enabled the type of modulation (logical AND or OR) can be selected by setting the PORTD2 Register as
'0' for AND, ‘1’ for OR.
The line at 19.11.8 TC3 Control Register A and 19.11.15 TC4 Control Register A (p198) are very easily missed, and should be a note in the tables 19.8, 19.13 etc.
For OC3B or OC4B when not using the Output Compare Modulator, PORTD2 must also be set in order to
enable the output.
Honestly it's a great feature, but it really needs flagging!
Testing
Tested on bare ATMega328PB datecode 2239 with the following:
No output on Pin 32
DDRD=04 PORTD=00
TCCR3A=82 TCCR3B=19 TCCR3C=00 ICR3=ffff OCR3A=0000 OCR3B=0000
T3: (A=10,B=00,W=1110,N=0,E=0,S=001,F=00)
TCCR4A=a2 TCCR4B=19 TCCR4C=00 ICR4=ffff OCR4A=0000 OCR4B=8000
T4: (A=10,B=10,W=1110,N=0,E=0,S=001,F=00)
Output on Pin 32
DDRD=04 PORTD=04
TCCR3A=82 TCCR3B=19 TCCR3C=00 ICR3=ffff OCR3A=0000 OCR3B=0000
T3: (A=10,B=00,W=1110,N=0,E=0,S=001,F=00)
TCCR4A=a2 TCCR4B=19 TCCR4C=00 ICR4=ffff OCR4A=0000 OCR4B=8000
T4: (A=10,B=10,W=1110,N=0,E=0,S=001,F=00)
from atmega328pb-testing.
Related Issues (20)
- Port Manipulation Problem HOT 1
- Cannot compile HOT 4
- High power consumption in deep sleep HOT 2
- SPCR, SPDR, and SPSR are not declared in the scope HOT 1
- compile error #include <twi_def.h> HOT 1
- Upload bootloader fail HOT 3
- ADC6 always reading 1023 HOT 1
- PlatformIO support HOT 2
- Explanation of Wire1 library HOT 1
- Precompiler issue with Wire.h HOT 2
- Bootloader and Sketch Upload with ISP works, Serial doesn't HOT 3
- Dead chips HOT 3
- Optiboot PB loader on Nano Clone no worky HOT 4
- Atmega328PB and RFM95W HOT 3
- USART1 instead of USART0 HOT 1
- Device signature error while uploading bootloader HOT 3
- m328pb flash programming using UART. HOT 1
- Problems with simultaneous master/slave HOT 3
- __AVR_HAVE_PRR0_PRTWI0 not correctly defined HOT 1
- SPI1 HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from atmega328pb-testing.