Skip to content

Commit 6feecc5

Browse files
me-no-devigrr
authored andcommitted
Fix analogWrite (#2299)
* Fix analogWrite Move to NMI interrupt Rework the whole ISR to take less and more constant cycles Current defaults run 10bits/1KHz@160MHz and 9bit/1KHz@80MHz (soft mapped) * astyle and remove STORE_ATTR
1 parent 9c36ff9 commit 6feecc5

File tree

1 file changed

+163
-106
lines changed

1 file changed

+163
-106
lines changed

cores/esp8266/core_esp8266_wiring_pwm.c

Lines changed: 163 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -24,132 +24,189 @@
2424
#include "eagle_soc.h"
2525
#include "ets_sys.h"
2626

27+
#ifndef F_CPU
28+
#define F_CPU 800000000L
29+
#endif
30+
31+
struct pwm_isr_table {
32+
uint8_t len;
33+
uint16_t steps[17];
34+
uint32_t masks[17];
35+
};
36+
37+
struct pwm_isr_data {
38+
struct pwm_isr_table tables[2];
39+
uint8_t active;//0 or 1, which table is active in ISR
40+
};
41+
42+
static struct pwm_isr_data _pwm_isr_data;
43+
2744
uint32_t pwm_mask = 0;
2845
uint16_t pwm_values[17] = {0,};
2946
uint32_t pwm_freq = 1000;
3047
uint32_t pwm_range = PWMRANGE;
3148

49+
uint8_t pwm_steps_changed = 0;
3250
uint32_t pwm_multiplier = 0;
33-
uint16_t pwm_steps[17];
34-
uint8_t pwm_steps_len = 0;
35-
uint32_t pwm_steps_mask[17];
36-
37-
int pwm_sort_array(uint16_t a[], uint16_t al){
38-
uint16_t i, j;
39-
for (i = 1; i < al; i++) {
40-
uint16_t tmp = a[i];
41-
for (j = i; j >= 1 && tmp < a[j-1]; j--)
42-
a[j] = a[j-1];
43-
a[j] = tmp;
44-
}
45-
int bl = 1;
46-
for(i = 1; i < al; i++){
47-
if(a[i] != a[i-1]) a[bl++] = a[i];
48-
}
49-
return bl;
51+
52+
int pwm_sort_array(uint16_t a[], uint16_t al)
53+
{
54+
uint16_t i, j;
55+
for (i = 1; i < al; i++) {
56+
uint16_t tmp = a[i];
57+
for (j = i; j >= 1 && tmp < a[j-1]; j--) {
58+
a[j] = a[j-1];
59+
}
60+
a[j] = tmp;
61+
}
62+
int bl = 1;
63+
for(i = 1; i < al; i++) {
64+
if(a[i] != a[i-1]) {
65+
a[bl++] = a[i];
66+
}
67+
}
68+
return bl;
5069
}
5170

52-
uint32_t pwm_get_mask(uint16_t value){
53-
uint32_t mask = 0;
54-
int i;
55-
for(i=0; i<17; i++){
56-
if((pwm_mask & (1 << i)) != 0 && pwm_values[i] == value) mask |= (1 << i);
57-
}
58-
return mask;
71+
uint32_t pwm_get_mask(uint16_t value)
72+
{
73+
uint32_t mask = 0;
74+
int i;
75+
for(i=0; i<17; i++) {
76+
if((pwm_mask & (1 << i)) != 0 && pwm_values[i] == value) {
77+
mask |= (1 << i);
78+
}
79+
}
80+
return mask;
5981
}
6082

61-
void prep_pwm_steps(){
62-
if(pwm_mask == 0){
63-
pwm_steps_len = 0;
64-
return;
65-
}
66-
67-
int pwm_temp_steps_len = 0;
68-
uint16_t pwm_temp_steps[17];
69-
uint32_t pwm_temp_masks[17];
70-
71-
int i;
72-
for(i=0; i<17; i++){
73-
if((pwm_mask & (1 << i)) != 0 && pwm_values[i] != 0) pwm_temp_steps[pwm_temp_steps_len++] = pwm_values[i];
74-
}
75-
pwm_temp_steps[pwm_temp_steps_len++] = pwm_range;
76-
pwm_temp_steps_len = pwm_sort_array(pwm_temp_steps, pwm_temp_steps_len) - 1;
77-
for(i=0; i<pwm_temp_steps_len; i++){
78-
pwm_temp_masks[i] = pwm_get_mask(pwm_temp_steps[i]);
79-
}
80-
for(i=pwm_temp_steps_len; i>0; i--){
81-
pwm_temp_steps[i] = pwm_temp_steps[i] - pwm_temp_steps[i-1];
82-
}
83-
ETS_FRC1_INTR_DISABLE();
84-
pwm_steps_len = pwm_temp_steps_len;
85-
ets_memcpy(pwm_steps, pwm_temp_steps, (pwm_temp_steps_len + 1) * 2);
86-
ets_memcpy(pwm_steps_mask, pwm_temp_masks, pwm_temp_steps_len * 4);
87-
pwm_multiplier = ESP8266_CLOCK/(pwm_range * pwm_freq);
88-
ETS_FRC1_INTR_ENABLE();
83+
void prep_pwm_steps()
84+
{
85+
if(pwm_mask == 0) {
86+
return;
87+
}
88+
89+
int pwm_temp_steps_len = 0;
90+
uint16_t pwm_temp_steps[17];
91+
uint32_t pwm_temp_masks[17];
92+
uint32_t range = pwm_range;
93+
94+
if((F_CPU / ESP8266_CLOCK) == 1) {
95+
range /= 2;
96+
}
97+
98+
int i;
99+
for(i=0; i<17; i++) {
100+
if((pwm_mask & (1 << i)) != 0 && pwm_values[i] != 0) {
101+
pwm_temp_steps[pwm_temp_steps_len++] = pwm_values[i];
102+
}
103+
}
104+
pwm_temp_steps[pwm_temp_steps_len++] = range;
105+
pwm_temp_steps_len = pwm_sort_array(pwm_temp_steps, pwm_temp_steps_len) - 1;
106+
for(i=0; i<pwm_temp_steps_len; i++) {
107+
pwm_temp_masks[i] = pwm_get_mask(pwm_temp_steps[i]);
108+
}
109+
for(i=pwm_temp_steps_len; i>0; i--) {
110+
pwm_temp_steps[i] = pwm_temp_steps[i] - pwm_temp_steps[i-1];
111+
}
112+
113+
pwm_steps_changed = 0;
114+
struct pwm_isr_table *table = &(_pwm_isr_data.tables[!_pwm_isr_data.active]);
115+
table->len = pwm_temp_steps_len;
116+
ets_memcpy(table->steps, pwm_temp_steps, (pwm_temp_steps_len + 1) * 2);
117+
ets_memcpy(table->masks, pwm_temp_masks, pwm_temp_steps_len * 4);
118+
pwm_multiplier = ESP8266_CLOCK/(range * pwm_freq);
119+
pwm_steps_changed = 1;
89120
}
90121

91-
void ICACHE_RAM_ATTR pwm_timer_isr(){
92-
static uint8_t current_step = 0;
93-
static uint8_t stepcount = 0;
94-
static uint16_t steps[17];
95-
static uint32_t masks[17];
96-
if(current_step < stepcount){
97-
T1L = (pwm_steps[current_step+1] * pwm_multiplier);
98-
TEIE |= TEIE1;
99-
if(masks[current_step] & 0xFFFF) GPOC = masks[current_step] & 0xFFFF;
100-
if(masks[current_step] & 0x10000) GP16O = 0;
101-
current_step++;
102-
} else {
103-
current_step = 0;
104-
stepcount = 0;
105-
if(pwm_mask == 0) return;
106-
T1L = (pwm_steps[current_step] * pwm_multiplier);
107-
TEIE |= TEIE1;
108-
if(pwm_mask & 0xFFFF) GPOS = pwm_mask & 0xFFFF;
109-
if(pwm_mask & 0x10000) GP16O = 1;
110-
stepcount = pwm_steps_len;
111-
memcpy(steps, pwm_steps, (stepcount + 1) * 2);
112-
memcpy(masks, pwm_steps_mask, stepcount * 4);
113-
}
122+
void ICACHE_RAM_ATTR pwm_timer_isr() //103-138
123+
{
124+
struct pwm_isr_table *table = &(_pwm_isr_data.tables[_pwm_isr_data.active]);
125+
static uint8_t current_step = 0;
126+
TEIE &= ~TEIE1;//14
127+
T1I = 0;//9
128+
if(current_step < table->len) { //20/21
129+
if(table->masks[current_step] & 0xFFFF) {
130+
GPOC = table->masks[current_step] & 0xFFFF; //15/21
131+
}
132+
if(table->masks[current_step] & 0x10000) {
133+
GP16O = 0; //6/13
134+
}
135+
current_step++;//1
136+
} else {
137+
current_step = 0;//1
138+
if(pwm_mask == 0) { //12
139+
table->len = 0;
140+
return;
141+
}
142+
if(pwm_mask & 0xFFFF) {
143+
GPOS = pwm_mask & 0xFFFF; //11
144+
}
145+
if(pwm_mask & 0x10000) {
146+
GP16O = 1; //5/13
147+
}
148+
if(pwm_steps_changed) { //12/21
149+
_pwm_isr_data.active = !_pwm_isr_data.active;
150+
table = &(_pwm_isr_data.tables[_pwm_isr_data.active]);
151+
pwm_steps_changed = 0;
152+
}
153+
}
154+
T1L = (table->steps[current_step] * pwm_multiplier);//23
155+
TEIE |= TEIE1;//13
114156
}
115157

116-
void pwm_start_timer(){
117-
timer1_disable();
118-
timer1_attachInterrupt(pwm_timer_isr);
119-
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
120-
timer1_write(1);
158+
void pwm_start_timer()
159+
{
160+
timer1_disable();
161+
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
162+
ETS_FRC_TIMER1_NMI_INTR_ATTACH(pwm_timer_isr);
163+
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
164+
timer1_write(1);
121165
}
122166

123-
extern void __analogWrite(uint8_t pin, int value) {
124-
bool start_timer = false;
125-
if(value == 0){
126-
pwm_mask &= ~(1 << pin);
127-
prep_pwm_steps();
128-
digitalWrite(pin, LOW);
129-
if(pwm_mask == 0) timer1_disable();
130-
return;
131-
}
132-
if((pwm_mask & (1 << pin)) == 0){
133-
if(pwm_mask == 0) start_timer = true;
134-
pwm_mask |= (1 << pin);
135-
pinMode(pin, OUTPUT);
136-
digitalWrite(pin, LOW);
137-
}
138-
pwm_values[pin] = value % (pwm_range + 1);
139-
prep_pwm_steps();
140-
if(start_timer){
141-
pwm_start_timer();
142-
}
167+
extern void __analogWrite(uint8_t pin, int value)
168+
{
169+
bool start_timer = false;
170+
if(value == 0) {
171+
pwm_mask &= ~(1 << pin);
172+
prep_pwm_steps();
173+
digitalWrite(pin, LOW);
174+
if(pwm_mask == 0) {
175+
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
176+
timer1_disable();
177+
timer1_isr_init();
178+
}
179+
return;
180+
}
181+
if((pwm_mask & (1 << pin)) == 0) {
182+
if(pwm_mask == 0) {
183+
memset(&_pwm_isr_data, 0, sizeof(struct pwm_isr_data*));
184+
start_timer = true;
185+
}
186+
pwm_mask |= (1 << pin);
187+
pinMode(pin, OUTPUT);
188+
digitalWrite(pin, LOW);
189+
}
190+
if((F_CPU / ESP8266_CLOCK) == 1) {
191+
value = (value+1) / 2;
192+
}
193+
pwm_values[pin] = value % (pwm_range + 1);
194+
prep_pwm_steps();
195+
if(start_timer) {
196+
pwm_start_timer();
197+
}
143198
}
144199

145-
extern void __analogWriteFreq(uint32_t freq){
146-
pwm_freq = freq;
147-
prep_pwm_steps();
200+
extern void __analogWriteFreq(uint32_t freq)
201+
{
202+
pwm_freq = freq;
203+
prep_pwm_steps();
148204
}
149205

150-
extern void __analogWriteRange(uint32_t range){
151-
pwm_range = range;
152-
prep_pwm_steps();
206+
extern void __analogWriteRange(uint32_t range)
207+
{
208+
pwm_range = range;
209+
prep_pwm_steps();
153210
}
154211

155212
extern void analogWrite(uint8_t pin, int val) __attribute__ ((weak, alias("__analogWrite")));

0 commit comments

Comments
 (0)