2018-12-03 20:44:06 +01:00
|
|
|
#ifndef _LowLevel_h
|
|
|
|
#define _LowLevel_h
|
|
|
|
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
|
|
|
#ifdef VS_INTELLISENSE
|
|
|
|
#define __attribute__(...)
|
|
|
|
#define digitalPinToPort(pin) 0
|
|
|
|
#define digitalPinToBitMask(pin) 0
|
|
|
|
#define portInputRegister(arg1) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ARDUINO >= 100
|
|
|
|
#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc
|
|
|
|
#else
|
|
|
|
#include "WProgram.h" // for delayMicroseconds
|
|
|
|
#include "pins_arduino.h" // for digitalPinToBitMask, etc
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__AVR__)
|
|
|
|
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
|
|
|
|
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
|
|
|
#define IO_REG_TYPE uint8_t
|
|
|
|
#define IO_REG_ASM asm("r30")
|
|
|
|
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
|
|
|
|
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask))
|
|
|
|
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask))
|
|
|
|
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask))
|
|
|
|
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
|
|
|
|
|
|
|
|
#if defined (__AVR_ATtiny85__)
|
2018-12-10 09:52:46 +01:00
|
|
|
|
|
|
|
/* Note : The attiny85 clock speed = 16mhz (fuses L 0xF1, H 0xDF. E oxFF
|
|
|
|
OSCCAL VALUE must also be calibrated to 16mhz
|
|
|
|
|
|
|
|
*/
|
|
|
|
#define CLEARINTERRUPT GIFR |= (1 << INTF0) | (1<<PCIF);
|
|
|
|
#define USERTIMER_COMPA_vect TIMER1_COMPA_vect
|
|
|
|
|
2018-12-03 20:44:06 +01:00
|
|
|
__attribute__((always_inline)) static inline void UserTimer_Init( void )
|
|
|
|
{
|
2018-12-10 09:52:46 +01:00
|
|
|
TCCR1 = 0; //stop the timer
|
|
|
|
TCNT1 = 0;
|
|
|
|
//GTCCR |= (1<<PSR1); //reset the prescaler
|
|
|
|
TIMSK = 0; // clear timer interrupts enable
|
2018-12-03 20:44:06 +01:00
|
|
|
}
|
2018-12-10 09:52:46 +01:00
|
|
|
__attribute__((always_inline)) static inline void UserTimer_Run(int skipTicks)
|
2018-12-03 20:44:06 +01:00
|
|
|
{
|
2018-12-10 09:52:46 +01:00
|
|
|
|
|
|
|
TCNT1 = 0; //zero the timer
|
|
|
|
GTCCR |= (1 << PSR1); //reset the prescaler
|
|
|
|
OCR1A = skipTicks; //set the compare value
|
|
|
|
TCCR1 |= (1 << CTC1) | (0 << CS13) | (1 << CS12) | (1 << CS11) | (0 << CS10);//32 prescaler
|
|
|
|
//TCCR1 |= (1 << CTC1) | (0 << CS13) | (1 << CS12) | (0 << CS11) | (0 << CS10);//8 prescaler
|
|
|
|
TIMSK |= (1 << OCIE1A); //interrupt on Compare Match A
|
2018-12-03 20:44:06 +01:00
|
|
|
}
|
2018-12-10 09:52:46 +01:00
|
|
|
|
|
|
|
__attribute__((always_inline)) static inline void UserTimer_Stop()
|
|
|
|
{
|
|
|
|
TIMSK = 0; //&= ~(1 << OCIE1A);// clear timer interrupt enable
|
|
|
|
TCCR1 = 0;
|
|
|
|
}
|
|
|
|
|
2018-12-03 20:44:06 +01:00
|
|
|
|
|
|
|
#elif defined (__AVR_ATmega328P__)
|
|
|
|
#define CLEARINTERRUPT EIFR |= (1 << INTF0)
|
|
|
|
#define USERTIMER_COMPA_vect TIMER1_COMPA_vect
|
|
|
|
|
|
|
|
__attribute__((always_inline)) static inline void UserTimer_Init( void )
|
|
|
|
{
|
|
|
|
TCCR1A = 0;
|
|
|
|
TCCR1B = 0;
|
2018-12-10 09:52:46 +01:00
|
|
|
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
|
2018-12-03 20:44:06 +01:00
|
|
|
}
|
|
|
|
__attribute__((always_inline)) static inline void UserTimer_Run(short skipTicks)
|
|
|
|
{
|
|
|
|
TCNT1 = 0;
|
|
|
|
OCR1A = skipTicks;
|
|
|
|
// turn on CTC mode with 64 prescaler
|
|
|
|
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
|
|
|
|
}
|
|
|
|
#define UserTimer_Stop() TCCR1B = 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#elif defined(__MK20DX128__) || defined(__MK20DX256__)
|
|
|
|
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
|
|
|
#define PIN_TO_BITMASK(pin) (1)
|
|
|
|
#define IO_REG_TYPE uint8_t
|
|
|
|
#define IO_REG_ASM
|
|
|
|
#define DIRECT_READ(base, mask) (*((base)+512))
|
|
|
|
#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0)
|
|
|
|
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1)
|
|
|
|
#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1)
|
|
|
|
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1)
|
|
|
|
|
|
|
|
#elif defined(__SAM3X8E__)
|
|
|
|
// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due.
|
|
|
|
// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268
|
|
|
|
// If you have trouble with OneWire on Arduino Due, please check the
|
|
|
|
// status of delayMicroseconds() before reporting a bug in OneWire!
|
|
|
|
#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER))
|
|
|
|
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
|
|
|
#define IO_REG_TYPE uint32_t
|
|
|
|
#define IO_REG_ASM
|
|
|
|
#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0)
|
|
|
|
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask))
|
|
|
|
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask))
|
|
|
|
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask))
|
|
|
|
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask))
|
|
|
|
#ifndef PROGMEM
|
|
|
|
#define PROGMEM
|
|
|
|
#endif
|
|
|
|
#ifndef pgm_read_byte
|
|
|
|
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#elif defined(__PIC32MX__)
|
|
|
|
#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin)))
|
|
|
|
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
|
|
|
#define IO_REG_TYPE uint32_t
|
|
|
|
#define IO_REG_ASM
|
|
|
|
#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10
|
|
|
|
#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08
|
|
|
|
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04
|
|
|
|
#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24
|
|
|
|
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28
|
|
|
|
|
|
|
|
#else
|
|
|
|
#error "Please define I/O register types here"
|
|
|
|
#endif
|
|
|
|
|
2018-12-10 09:52:46 +01:00
|
|
|
|
2018-12-03 20:44:06 +01:00
|
|
|
class Pin
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
volatile IO_REG_TYPE *reg_;
|
|
|
|
IO_REG_TYPE mask_;
|
|
|
|
byte interruptNumber_;
|
|
|
|
byte pinNumber_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Pin()
|
|
|
|
: mask_(0)
|
|
|
|
, reg_(0)
|
|
|
|
, interruptNumber_((byte) - 1)
|
|
|
|
, pinNumber_(255)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
Pin(uint8_t pin)
|
|
|
|
{
|
|
|
|
pinNumber_ = pin;
|
|
|
|
mask_ = PIN_TO_BITMASK(pin);
|
|
|
|
reg_ = PIN_TO_BASEREG(pin);
|
|
|
|
|
|
|
|
switch (pin)
|
|
|
|
{
|
|
|
|
case 2: interruptNumber_ = 0; break;
|
|
|
|
case 3: interruptNumber_ = 1; break;
|
|
|
|
default: interruptNumber_ = (byte) - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline byte getPinNumber() {
|
|
|
|
return pinNumber_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void inputMode() {
|
|
|
|
DIRECT_MODE_INPUT(reg_, mask_);
|
|
|
|
}
|
|
|
|
inline void outputMode() {
|
|
|
|
DIRECT_MODE_OUTPUT(reg_, mask_);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool read() {
|
|
|
|
return DIRECT_READ(reg_, mask_) == 1;
|
|
|
|
}
|
|
|
|
inline void writeLow() {
|
|
|
|
DIRECT_WRITE_LOW(reg_, mask_);
|
|
|
|
}
|
|
|
|
inline void writeHigh() {
|
|
|
|
DIRECT_WRITE_HIGH(reg_, mask_);
|
|
|
|
}
|
|
|
|
inline void write(bool value) {
|
|
|
|
if (value) writeHigh();
|
|
|
|
else writeLow();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void attachInterrupt(void (*handler)(), int mode)
|
|
|
|
{
|
|
|
|
CLEARINTERRUPT; // clear any pending interrupt (we want to call the handler only for interrupts happening after it is attached)
|
|
|
|
::attachInterrupt(interruptNumber_, handler, mode);
|
|
|
|
}
|
2018-12-10 09:52:46 +01:00
|
|
|
|
2018-12-03 20:44:06 +01:00
|
|
|
inline void detachInterrupt() {
|
|
|
|
::detachInterrupt(interruptNumber_);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|