Skip to content
This repository
Browse code

Optimized digitalWrite(), etc. from Alvaro Lopez.

  • Loading branch information...
commit 9dccd634c5ff1fed88459e39b277794dbba039fb 1 parent 80bb16d
David A. Mellis authored February 11, 2011
452  hardware/arduino/cores/arduino/pins_arduino.h
@@ -49,6 +49,10 @@
49 49
 #define TIMER5B 15
50 50
 #define TIMER5C 16
51 51
 
  52
+#ifndef INLINED
  53
+#define INLINED static __attribute__((always_inline)) inline
  54
+#endif
  55
+
52 56
 #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
53 57
 const static uint8_t SS   = 53;
54 58
 const static uint8_t MOSI = 51;
@@ -72,17 +76,447 @@ extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
72 76
 extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
73 77
 extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
74 78
 
  79
+// inlined versions of lookup-table-based pin mappings. Don't use directly.
  80
+
  81
+// Don't use PA, so on, might clash with sketch
  82
+
  83
+#define PORT_INDEX_PA 1
  84
+#define PORT_INDEX_PB 2
  85
+#define PORT_INDEX_PC 3
  86
+#define PORT_INDEX_PD 4
  87
+#define PORT_INDEX_PE 5
  88
+#define PORT_INDEX_PF 6
  89
+#define PORT_INDEX_PG 7
  90
+#define PORT_INDEX_PH 8
  91
+#define PORT_INDEX_PJ 10
  92
+#define PORT_INDEX_PK 11
  93
+#define PORT_INDEX_PL 12
  94
+
  95
+__attribute__((error("Invalid pin specified. This pin does not map to any I/O port"))) static void invalidPinSpecified(void);
  96
+
  97
+
  98
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  99
+
  100
+INLINED volatile uint8_t *inlined_portModeRegister(uint8_t port_index)
  101
+{
  102
+	switch (port_index) {
  103
+	case 1: return &DDRA;
  104
+	case 2: return &DDRB;
  105
+	case 3: return &DDRC;
  106
+	case 4: return &DDRD;
  107
+	case 5: return &DDRE;
  108
+	case 6: return &DDRF;
  109
+	case 7: return &DDRG;
  110
+	case 8: return &DDRH;
  111
+	case 10: return &DDRJ;
  112
+	case 11: return &DDRK;
  113
+	case 12: return &DDRL;
  114
+	default: return NOT_A_PORT;
  115
+	}
  116
+}
  117
+
  118
+INLINED volatile uint8_t *inlined_portOutputRegister(uint8_t port_index)
  119
+{
  120
+	switch (port_index) {
  121
+	case 1: return &PORTA;
  122
+	case 2: return &PORTB;
  123
+	case 3: return &PORTC;
  124
+	case 4: return &PORTD;
  125
+	case 5: return &PORTE;
  126
+	case 6: return &PORTF;
  127
+	case 7: return &PORTG;
  128
+	case 8: return &PORTH;
  129
+	case 10: return &PORTJ;
  130
+	case 11: return &PORTK;
  131
+	case 12: return &PORTL;
  132
+	default: return NOT_A_PORT;
  133
+	}
  134
+}
  135
+
  136
+INLINED volatile uint8_t *inlined_portInputRegister(uint8_t port_index)
  137
+{
  138
+	switch (port_index) {
  139
+	case 1: return &PINA;
  140
+	case 2: return &PINB;
  141
+	case 3: return &PINC;
  142
+	case 4: return &PIND;
  143
+	case 5: return &PINE;
  144
+	case 6: return &PINF;
  145
+	case 7: return &PING;
  146
+	case 8: return &PINH;
  147
+	case 10: return &PINJ;
  148
+	case 11: return &PINK;
  149
+	case 12: return &PINL;
  150
+	default: return NOT_A_PIN;
  151
+	}
  152
+};
  153
+
  154
+INLINED uint8_t inlined_digitalPinToPort(uint8_t pin)
  155
+{
  156
+	switch (pin) {
  157
+	case 0:  // PE 0 ** 0 ** USART0_RX
  158
+	case 1:  // PE 1 ** 1 ** USART0_TX
  159
+	case 2:  // PE 4 ** 2 ** PWM2
  160
+	case 3:  // PE 5 ** 3 ** PWM3
  161
+		return PORT_INDEX_PE;
  162
+
  163
+	case 4:  // PG 5 ** 4 ** PWM4
  164
+		return PORT_INDEX_PG;
  165
+
  166
+	case 5:  // PE 3 ** 5 ** PWM5
  167
+		return PORT_INDEX_PE;
  168
+
  169
+	case 6:  // PH 3 ** 6 ** PWM6
  170
+	case 7:  // PH 4 ** 7 ** PWM7
  171
+	case 8:  // PH 5 ** 8 ** PWM8
  172
+	case 9:  // PH 6 ** 9 ** PWM9
  173
+		return PORT_INDEX_PH;
  174
+
  175
+	case 10: // PB 4 ** 10 ** PWM10
  176
+	case 11: // PB 5 ** 11 ** PWM11
  177
+	case 12: // PB 6 ** 12 ** PWM12
  178
+	case 13: // PB 7 ** 13 ** PWM13
  179
+		return PORT_INDEX_PB;
  180
+
  181
+	case 14: // PJ 1 ** 14 ** USART3_TX
  182
+	case 15: // PJ 0 ** 15 ** USART3_RX
  183
+		return PORT_INDEX_PJ;
  184
+
  185
+	case 16: // PH 1 ** 16 ** USART2_TX
  186
+	case 17: // PH 0 ** 17 ** USART2_RX
  187
+		return PORT_INDEX_PH;
  188
+
  189
+	case 18: // PD 3 ** 18 ** USART1_TX
  190
+	case 19: // PD 2 ** 19 ** USART1_RX
  191
+	case 20: // PD 1 ** 20 ** I2C_SDA
  192
+	case 21: // PD 0 ** 21 ** I2C_SCL
  193
+		return PORT_INDEX_PD;
  194
+
  195
+	case 22: // PA 0 ** 22 ** D22
  196
+	case 23: // PA 1 ** 23 ** D23
  197
+	case 24: // PA 2 ** 24 ** D24
  198
+	case 25: // PA 3 ** 25 ** D25
  199
+	case 26: // PA 4 ** 26 ** D26
  200
+	case 27: // PA 5 ** 27 ** D27
  201
+	case 28: // PA 6 ** 28 ** D28
  202
+	case 29: // PA 7 ** 29 ** D29
  203
+		return PORT_INDEX_PA;
  204
+
  205
+	case 30: // PC 7 ** 30 ** D30
  206
+	case 31: // PC 6 ** 31 ** D31
  207
+	case 32: // PC 5 ** 32 ** D32
  208
+	case 33: // PC 4 ** 33 ** D33
  209
+	case 34: // PC 3 ** 34 ** D34
  210
+	case 35: // PC 2 ** 35 ** D35
  211
+	case 36: // PC 1 ** 36 ** D36
  212
+	case 37: // PC 0 ** 37 ** D37
  213
+		return PORT_INDEX_PC;
  214
+
  215
+	case 38: // PD 7 ** 38 ** D38
  216
+		return PORT_INDEX_PD;
  217
+
  218
+	case 39: // PG 2 ** 39 ** D39
  219
+	case 40: // PG 1 ** 40 ** D40
  220
+	case 41: // PG 0 ** 41 ** D41
  221
+		return PORT_INDEX_PG;
  222
+
  223
+	case 42: // PL 7 ** 42 ** D42
  224
+	case 43: // PL 6 ** 43 ** D43
  225
+	case 44: // PL 5 ** 44 ** D44
  226
+	case 45: // PL 4 ** 45 ** D45
  227
+	case 46: // PL 3 ** 46 ** D46
  228
+	case 47: // PL 2 ** 47 ** D47
  229
+	case 48: // PL 1 ** 48 ** D48
  230
+	case 49: // PL 0 ** 49 ** D49
  231
+		return PORT_INDEX_PL;
  232
+
  233
+	case 50: // PB 3 ** 50 ** SPI_MISO
  234
+	case 51: // PB 2 ** 51 ** SPI_MOSI
  235
+	case 52: // PB 1 ** 52 ** SPI_SCK
  236
+	case 53: // PB 0 ** 53 ** SPI_SS
  237
+		return PORT_INDEX_PB;
  238
+
  239
+	case 54: // PF 0 ** 54 ** A0
  240
+	case 55: // PF 1 ** 55 ** A1
  241
+	case 56: // PF 2 ** 56 ** A2
  242
+	case 57: // PF 3 ** 57 ** A3
  243
+	case 58: // PF 4 ** 58 ** A4
  244
+	case 59: // PF 5 ** 59 ** A5
  245
+	case 60: // PF 6 ** 60 ** A6
  246
+	case 61: // PF 7 ** 61 ** A7
  247
+		return PORT_INDEX_PF;
  248
+
  249
+	case 62: // PK 0 ** 62 ** A8
  250
+	case 63: // PK 1 ** 63 ** A9
  251
+	case 64: // PK 2 ** 64 ** A10
  252
+	case 65: // PK 3 ** 65 ** A11
  253
+	case 66: // PK 4 ** 66 ** A12
  254
+	case 67: // PK 5 ** 67 ** A13
  255
+	case 68: // PK 6 ** 68 ** A14
  256
+	case 69: // PK 7 ** 69 ** A15
  257
+		return PORT_INDEX_PK;
  258
+	default:
  259
+		invalidPinSpecified();
  260
+	}
  261
+}
  262
+
  263
+INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin)
  264
+{
  265
+	switch(pin) {
  266
+	case  0: return _BV( 0 ); // PE 0 ** 0 ** USART0_RX
  267
+	case  1: return _BV( 1 ); // PE 1 ** 1 ** USART0_TX
  268
+	case  2: return _BV( 4 ); // PE 4 ** 2 ** PWM2
  269
+	case  3: return _BV( 5 ); // PE 5 ** 3 ** PWM3
  270
+	case  4: return _BV( 5 ); // PG 5 ** 4 ** PWM4
  271
+	case  5: return _BV( 3 ); // PE 3 ** 5 ** PWM5
  272
+	case  6: return _BV( 3 ); // PH 3 ** 6 ** PWM6
  273
+	case  7: return _BV( 4 ); // PH 4 ** 7 ** PWM7
  274
+	case  8: return _BV( 5 ); // PH 5 ** 8 ** PWM8
  275
+	case  9: return _BV( 6 ); // PH 6 ** 9 ** PWM9
  276
+	case 10: return _BV( 4 ); // PB 4 ** 10 ** PWM10
  277
+	case 11: return _BV( 5 ); // PB 5 ** 11 ** PWM11
  278
+	case 12: return _BV( 6 ); // PB 6 ** 12 ** PWM12
  279
+	case 13: return _BV( 7 ); // PB 7 ** 13 ** PWM13
  280
+	case 14: return _BV( 1 ); // PJ 1 ** 14 ** USART3_TX
  281
+	case 15: return _BV( 0 ); // PJ 0 ** 15 ** USART3_RX
  282
+	case 16: return _BV( 1 ); // PH 1 ** 16 ** USART2_TX
  283
+	case 17: return _BV( 0 ); // PH 0 ** 17 ** USART2_RX
  284
+	case 18: return _BV( 3 ); // PD 3 ** 18 ** USART1_TX
  285
+	case 19: return _BV( 2 ); // PD 2 ** 19 ** USART1_RX
  286
+	case 20: return _BV( 1 ); // PD 1 ** 20 ** I2C_SDA
  287
+	case 21: return _BV( 0 ); // PD 0 ** 21 ** I2C_SCL
  288
+	case 22: return _BV( 0 ); // PA 0 ** 22 ** D22
  289
+	case 23: return _BV( 1 ); // PA 1 ** 23 ** D23
  290
+	case 24: return _BV( 2 ); // PA 2 ** 24 ** D24
  291
+	case 25: return _BV( 3 ); // PA 3 ** 25 ** D25
  292
+	case 26: return _BV( 4 ); // PA 4 ** 26 ** D26
  293
+	case 27: return _BV( 5 ); // PA 5 ** 27 ** D27
  294
+	case 28: return _BV( 6 ); // PA 6 ** 28 ** D28
  295
+	case 29: return _BV( 7 ); // PA 7 ** 29 ** D29
  296
+	case 30: return _BV( 7 ); // PC 7 ** 30 ** D30
  297
+	case 31: return _BV( 6 ); // PC 6 ** 31 ** D31
  298
+	case 32: return _BV( 5 ); // PC 5 ** 32 ** D32
  299
+	case 33: return _BV( 4 ); // PC 4 ** 33 ** D33
  300
+	case 34: return _BV( 3 ); // PC 3 ** 34 ** D34
  301
+	case 35: return _BV( 2 ); // PC 2 ** 35 ** D35
  302
+	case 36: return _BV( 1 ); // PC 1 ** 36 ** D36
  303
+	case 37: return _BV( 0 ); // PC 0 ** 37 ** D37
  304
+	case 38: return _BV( 7 ); // PD 7 ** 38 ** D38
  305
+	case 39: return _BV( 2 ); // PG 2 ** 39 ** D39
  306
+	case 40: return _BV( 1 ); // PG 1 ** 40 ** D40
  307
+	case 41: return _BV( 0 ); // PG 0 ** 41 ** D41
  308
+	case 42: return _BV( 7 ); // PL 7 ** 42 ** D42
  309
+	case 43: return _BV( 6 ); // PL 6 ** 43 ** D43
  310
+	case 44: return _BV( 5 ); // PL 5 ** 44 ** D44
  311
+	case 45: return _BV( 4 ); // PL 4 ** 45 ** D45
  312
+	case 46: return _BV( 3 ); // PL 3 ** 46 ** D46
  313
+	case 47: return _BV( 2 ); // PL 2 ** 47 ** D47
  314
+	case 48: return _BV( 1 ); // PL 1 ** 48 ** D48
  315
+	case 49: return _BV( 0 ); // PL 0 ** 49 ** D49
  316
+	case 50: return _BV( 3 ); // PB 3 ** 50 ** SPI_MISO
  317
+	case 51: return _BV( 2 ); // PB 2 ** 51 ** SPI_MOSI
  318
+	case 52: return _BV( 1 ); // PB 1 ** 52 ** SPI_SCK
  319
+	case 53: return _BV( 0 ); // PB 0 ** 53 ** SPI_SS
  320
+	case 54: return _BV( 0 ); // PF 0 ** 54 ** A0
  321
+	case 55: return _BV( 1 ); // PF 1 ** 55 ** A1
  322
+	case 56: return _BV( 2 ); // PF 2 ** 56 ** A2
  323
+	case 57: return _BV( 3 ); // PF 3 ** 57 ** A3
  324
+	case 58: return _BV( 4 ); // PF 4 ** 58 ** A4
  325
+	case 59: return _BV( 5 ); // PF 5 ** 59 ** A5
  326
+	case 60: return _BV( 6 ); // PF 6 ** 60 ** A6
  327
+	case 61: return _BV( 7 ); // PF 7 ** 61 ** A7
  328
+	case 62: return _BV( 0 ); // PK 0 ** 62 ** A8
  329
+	case 63: return _BV( 1 ); // PK 1 ** 63 ** A9
  330
+	case 64: return _BV( 2 ); // PK 2 ** 64 ** A10
  331
+	case 65: return _BV( 3 ); // PK 3 ** 65 ** A11
  332
+	case 66: return _BV( 4 ); // PK 4 ** 66 ** A12
  333
+	case 67: return _BV( 5 ); // PK 5 ** 67 ** A13
  334
+	case 68: return _BV( 6 ); // PK 6 ** 68 ** A14
  335
+	case 69: return _BV( 7 ); // PK 7 ** 69 ** A15
  336
+	default:
  337
+		// TODO: add error here
  338
+		invalidPinSpecified();
  339
+	}
  340
+}
  341
+
  342
+INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin)
  343
+{
  344
+	switch(pin) {
  345
+	case  2: return TIMER3B; // PE 4 ** 2 ** PWM2
  346
+	case  3: return TIMER3C; // PE 5 ** 3 ** PWM3
  347
+	case  4: return TIMER0B; // PG 5 ** 4 ** PWM4
  348
+	case  5: return TIMER3A; // PE 3 ** 5 ** PWM5
  349
+	case  6: return TIMER4A; // PH 3 ** 6 ** PWM6
  350
+	case  7: return TIMER4B; // PH 4 ** 7 ** PWM7
  351
+	case  8: return TIMER4C; // PH 5 ** 8 ** PWM8
  352
+	case  9: return TIMER2B; // PH 6 ** 9 ** PWM9
  353
+	case 10: return TIMER2A; // PB 4 ** 10 ** PWM10
  354
+	case 11: return TIMER1A; // PB 5 ** 11 ** PWM11
  355
+	case 12: return TIMER1B; // PB 6 ** 12 ** PWM12
  356
+	case 13: return TIMER0A; // PB 7 ** 13 ** PWM13
  357
+	case 44: return TIMER5C; // PL 5 ** 44 ** D44
  358
+	case 45: return TIMER5B; // PL 4 ** 45 ** D45
  359
+	case 46: return TIMER5A; // PL 3 ** 46 ** D46
  360
+	default: invalidPinSpecified();
  361
+	}
  362
+}
  363
+
  364
+#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  365
+
  366
+INLINED volatile uint8_t *inlined_portModeRegister(uint8_t port_index)
  367
+{
  368
+	switch (port_index) {
  369
+	case 2: return &DDRB;
  370
+	case 3: return &DDRC;
  371
+	case 4: return &DDRD;
  372
+	default: invalidPinSpecified();
  373
+	}
  374
+}
  375
+
  376
+INLINED volatile uint8_t *inlined_portOutputRegister(uint8_t port_index)
  377
+{
  378
+	switch (port_index) {
  379
+	case 2: return &PORTB;
  380
+	case 3: return &PORTC;
  381
+	case 4: return &PORTD;
  382
+	default: invalidPinSpecified();
  383
+	}
  384
+}
  385
+
  386
+INLINED volatile uint8_t *inlined_portInputRegister(uint8_t port_index)
  387
+{
  388
+	switch (port_index) {
  389
+	case 2: return &PINB;
  390
+	case 3: return &PINC;
  391
+	case 4: return &PIND;
  392
+	default: invalidPinSpecified();
  393
+	}
  394
+}
  395
+
  396
+INLINED uint8_t inlined_digitalPinToPort(uint8_t pin)
  397
+{
  398
+	switch(pin) {
  399
+	case 0:
  400
+	case 1:
  401
+	case 2:
  402
+	case 3:
  403
+	case 4:
  404
+	case 5:
  405
+	case 6:
  406
+	case 7:
  407
+		return PORT_INDEX_PD;
  408
+	case 8:
  409
+	case 9:
  410
+	case 10:
  411
+	case 11:
  412
+	case 12:
  413
+	case 13:
  414
+		return PORT_INDEX_PB;
  415
+	case 14:
  416
+	case 15:
  417
+	case 16:
  418
+	case 17:
  419
+	case 18:
  420
+	case 19:
  421
+		return PORT_INDEX_PC;
  422
+	default:
  423
+		invalidPinSpecified();
  424
+	}
  425
+}
  426
+
  427
+INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin)
  428
+{
  429
+	switch(pin) {
  430
+	case 0: return _BV(0); /* 0, port D */
  431
+	case 1: return _BV(1);
  432
+	case 2: return _BV(2);
  433
+	case 3: return _BV(3);
  434
+	case 4: return _BV(4);
  435
+	case 5: return _BV(5);
  436
+	case 6: return _BV(6);
  437
+	case 7: return _BV(7);
  438
+	case 8: return _BV(0); /* 8, port B */
  439
+	case 9: return _BV(1);
  440
+	case 10: return _BV(2);
  441
+	case 11: return _BV(3);
  442
+	case 12: return _BV(4);
  443
+	case 13: return _BV(5);
  444
+	case 14: return _BV(0); /* 14, port C */
  445
+	case 15: return _BV(1);
  446
+	case 16: return _BV(2);
  447
+	case 17: return _BV(3);
  448
+	case 18: return _BV(4);
  449
+	case 19: return _BV(5);
  450
+	default:
  451
+		// TODO: throw error here
  452
+		invalidPinSpecified();
  453
+	}
  454
+}
  455
+
  456
+INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin)
  457
+{
  458
+	switch(pin) {
  459
+#if defined(__AVR_ATmega8__)
  460
+	case 11: return TIMER2;
  461
+#else
  462
+	case  3: return TIMER2B;
  463
+	case  5: return TIMER0B;
  464
+	case  6: return TIMER0A;
  465
+	case 11: return TIMER2A;
  466
+#endif
  467
+	case  9: return TIMER1A;
  468
+	case 10: return TIMER1B;
  469
+	default: invalidPinSpecified();
  470
+	}
  471
+}
  472
+
  473
+#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  474
+
75 475
 // Get the bit location within the hardware port of the given virtual pin.
76 476
 // This comes from the pins_*.c file for the active board configuration.
77  
-// 
78  
-// These perform slightly better as macros compared to inline functions
79  
-//
80  
-#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
81  
-#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
82  
-#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
  477
+
83 478
 #define analogInPinToBit(P) (P)
84  
-#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
85  
-#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
86  
-#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
  479
+
  480
+INLINED uint8_t digitalPinToPort(uint8_t pin) {
  481
+	if (__builtin_constant_p(pin))
  482
+		return inlined_digitalPinToPort(pin);
  483
+	else
  484
+		return pgm_read_byte( digital_pin_to_port_PGM + pin );
  485
+}
  486
+
  487
+INLINED uint8_t digitalPinToBitMask(uint8_t pin) {
  488
+	if (__builtin_constant_p(pin))
  489
+		return inlined_digitalPinToBitMask(pin);
  490
+	else
  491
+		return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin );
  492
+}
  493
+
  494
+INLINED uint8_t digitalPinToTimer(uint8_t pin) {
  495
+	if (__builtin_constant_p(pin))
  496
+		return inlined_digitalPinToTimer(pin);
  497
+	else
  498
+		return pgm_read_byte( digital_pin_to_timer_PGM + pin );
  499
+}
  500
+
  501
+INLINED volatile uint8_t *portOutputRegister(uint8_t index) {
  502
+	if (__builtin_constant_p(index))
  503
+		return inlined_portOutputRegister(index);
  504
+	else
  505
+		return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) );
  506
+}
  507
+
  508
+INLINED volatile uint8_t* portInputRegister(uint8_t index) {
  509
+	if (__builtin_constant_p(index))
  510
+		return inlined_portInputRegister(index);
  511
+	else
  512
+		return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) );
  513
+}
  514
+
  515
+INLINED volatile uint8_t* portModeRegister(uint8_t index) {
  516
+	if (__builtin_constant_p(index))
  517
+		return inlined_portModeRegister(index);
  518
+	else
  519
+		return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) );
  520
+}
87 521
 
88 522
 #endif
73  hardware/arduino/cores/arduino/wiring.h
@@ -26,8 +26,10 @@
26 26
 #define Wiring_h
27 27
 
28 28
 #include <avr/io.h>
  29
+#include <avr/interrupt.h>
29 30
 #include <stdlib.h>
30 31
 #include "binary.h"
  32
+#include "pins_arduino.h"
31 33
 
32 34
 #ifdef __cplusplus
33 35
 extern "C"{
@@ -106,9 +108,9 @@ typedef uint8_t byte;
106 108
 
107 109
 void init(void);
108 110
 
109  
-void pinMode(uint8_t, uint8_t);
110  
-void digitalWrite(uint8_t, uint8_t);
111  
-int digitalRead(uint8_t);
  111
+void pinMode_lookup(uint8_t, uint8_t);
  112
+void digitalWrite_lookup(uint8_t, uint8_t);
  113
+int digitalRead_lookup(uint8_t);
112 114
 int analogRead(uint8_t);
113 115
 void analogReference(uint8_t mode);
114 116
 void analogWrite(uint8_t, int);
@@ -128,6 +130,71 @@ void detachInterrupt(uint8_t);
128 130
 void setup(void);
129 131
 void loop(void);
130 132
 
  133
+/*
  134
+ * Check if a given pin requires locking.
  135
+ * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However
  136
+ * other IO ports require load+modify+store and we need to make them atomic by disabling
  137
+ * interrupts.
  138
+ */
  139
+INLINED int portWriteNeedsLocking(uint8_t pin)
  140
+{
  141
+	/* SBI/CBI instructions only work on lower 32 IO ports */
  142
+	if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) {
  143
+		return 1;
  144
+	}
  145
+	return 0;
  146
+}
  147
+
  148
+/*
  149
+ * These functions will perform OR/AND on a given register, and are atomic.
  150
+ */
  151
+extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit);
  152
+extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit);
  153
+
  154
+INLINED void digitalWrite(uint8_t pin, uint8_t value)
  155
+{
  156
+	if (__builtin_constant_p(pin)) {
  157
+		if (portWriteNeedsLocking(pin)) {
  158
+			if (value==LOW) {
  159
+				__digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin));
  160
+			} else {
  161
+				__digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin));
  162
+			}
  163
+		} else {
  164
+			if (value==LOW) {
  165
+				*inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin));
  166
+			} else {
  167
+				*inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin);
  168
+			}
  169
+		}
  170
+	} else {
  171
+		digitalWrite_lookup(pin,value);
  172
+	}
  173
+}
  174
+
  175
+INLINED void pinMode(uint8_t pin, uint8_t mode)
  176
+{
  177
+	if (__builtin_constant_p(pin)) {
  178
+		if (mode==INPUT) {
  179
+			*inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin));
  180
+		} else {
  181
+			*inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin);
  182
+		}
  183
+	} else {
  184
+		pinMode_lookup(pin,mode);
  185
+	}
  186
+}
  187
+
  188
+INLINED int digitalRead(uint8_t pin)
  189
+{
  190
+	if (__builtin_constant_p(pin)) {
  191
+		return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin));
  192
+	} else {
  193
+		return digitalRead_lookup(pin);
  194
+	}
  195
+}
  196
+
  197
+
131 198
 #ifdef __cplusplus
132 199
 } // extern "C"
133 200
 #endif
33  hardware/arduino/cores/arduino/wiring_digital.c
@@ -27,7 +27,7 @@
27 27
 #include "wiring_private.h"
28 28
 #include "pins_arduino.h"
29 29
 
30  
-void pinMode(uint8_t pin, uint8_t mode)
  30
+void pinMode_lookup(uint8_t pin, uint8_t mode)
31 31
 {
32 32
 	uint8_t bit = digitalPinToBitMask(pin);
33 33
 	uint8_t port = digitalPinToPort(pin);
@@ -121,7 +121,23 @@ static void turnOffPWM(uint8_t timer)
121 121
 	}
122 122
 }
123 123
 
124  
-void digitalWrite(uint8_t pin, uint8_t val)
  124
+void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit)
  125
+{
  126
+	uint8_t oldSREG = SREG;
  127
+	cli();
  128
+	*out |= bit;
  129
+	SREG=oldSREG;
  130
+}
  131
+
  132
+void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit)
  133
+{
  134
+	uint8_t oldSREG = SREG;
  135
+	cli();
  136
+	*out &= bit; // NOTE - no inversion here, invert before calling!!!
  137
+	SREG=oldSREG;
  138
+}
  139
+
  140
+void digitalWrite_lookup(uint8_t pin, uint8_t val)
125 141
 {
126 142
 	uint8_t timer = digitalPinToTimer(pin);
127 143
 	uint8_t bit = digitalPinToBitMask(pin);
@@ -136,20 +152,19 @@ void digitalWrite(uint8_t pin, uint8_t val)
136 152
 
137 153
 	out = portOutputRegister(port);
138 154
 
  155
+	uint8_t oldSREG = SREG;
  156
+	cli();
  157
+
139 158
 	if (val == LOW) {
140  
-		uint8_t oldSREG = SREG;
141  
-                cli();
142 159
 		*out &= ~bit;
143  
-		SREG = oldSREG;
144 160
 	} else {
145  
-		uint8_t oldSREG = SREG;
146  
-                cli();
147 161
 		*out |= bit;
148  
-		SREG = oldSREG;
149 162
 	}
  163
+
  164
+	SREG = oldSREG;
150 165
 }
151 166
 
152  
-int digitalRead(uint8_t pin)
  167
+int digitalRead_lookup(uint8_t pin)
153 168
 {
154 169
 	uint8_t timer = digitalPinToTimer(pin);
155 170
 	uint8_t bit = digitalPinToBitMask(pin);

0 notes on commit 9dccd63

Please sign in to comment.
Something went wrong with that request. Please try again.