Skip to content
This repository was archived by the owner on Jan 23, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Arduino library for SBUS (Futaba)

SBUS library supports synchronous (blocking) or asynchronous (non-blocking) decoding of Futaba SBUS **without** requiring a **TTL inverter**.

SBUS uses the TIMER 2 and the Pin Change interrupt. It doesn't use UARTs, so those pins can be used:
SBUS uses the TIMER 0 and the Pin Change interrupt. It doesn't use UARTs, so those pins can be used:
```
Arduino Uno/Nano/Mini: All pins are usable
Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64),
Expand Down Expand Up @@ -59,6 +59,34 @@ void loop() {

sbus.waitFrame() needs to be called. It returns "false" on timeout (default is 2 seconds). sbus.waitFrame() waits for the next frame the returns.

===== Additional Notes =====

Thank you to fdivitto. Your work is awesome!

Supported Pins
For unlisted boards,
1. Check the interrupt vector table for listing of PCINTx_vect
2. Chip pinouts for PCINTx, corresponding to PCINTx_vect
3. TIMER0 is an 8-bit timer

ATMega328P (Uno, Nano):
ISRN(0): D8,D9,D10,D11,D12,D13
ISRN(1): A0,A1,A2,A3,A4,A5,D0,D1
ISRN(2): D2,D3,D4,D5,D6,D7
VERIFIED 8-BIT TIMER ON TC0 and TC2

ATMega32u4 (Leonardo, Micro):
ISRN(0): SS(PB0),SCK(PB1),MOSI(PB2),MISO(PB3),8,9,10,11
VERIFIED 8BIT TIMER ON TC0

ATMega2560 (Mega2560):
ISRN(0): SS(PB0),SCK(PB1),MOSI(PB2),MISO(PB3),D1,D10,D11,D12,D13
ISRN(1): D0,D15,D14
ISRN(2): A8,A9,A10,A11,A12,A13,A14,A15
VERIFIED 8-BIT TIMER ON TC0

===== CHANGES =====
Changed TIMER2 to TIMER0 for support for more boards; especially the ATMega32u4
Conditional ISR for PinChangeInterrupt, since the smaller boards only have PCINT0_vect interrupt vector.


40 changes: 24 additions & 16 deletions sbus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
sbus.cpp

Copyright (c) 2017, Fabrizio Di Vittorio (fdivitto2013@gmail.com)
Edited by ultimate1112.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
Expand All @@ -21,7 +22,7 @@
#include "sbus.h"


// quick IO functions
// Quick IO functions
#define portOfPin(P) portOutputRegister(digitalPinToPort(P))
#define ddrOfPin(P) portModeRegister(digitalPinToPort(P))
#define pinOfPin(P) portInputRegister(digitalPinToPort(P))
Expand Down Expand Up @@ -89,42 +90,49 @@ inline void disablePinChangeInterrupts()
}


// handle pin change interrupt here
// Handle pin change interrupt here
static void handleInterrupt();
#define ISRN(N) ISR(PCINT ## N ## _vect) { if (s_PCICRMask == 1 << (N)) handleInterrupt(); }
ISRN(0) ISRN(1) ISRN(2)

// Define Pin Change Interrupts for specific board
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega328P__)
ISRN(0) ISRN(1) ISRN(2)
#else
// Fall back to PCINT[0-7]
ISRN(0)
#endif

static void handleInterrupt()
{

// start bit?
if (pinGet(s_pin, s_pinMask)) {

// reset timer 2 counter
TCNT2 = 0;
// reset timer 0 counter
TCNT0 = 0;

disablePinChangeInterrupts();

// start bit received
uint8_t receivingWord = 0;

// reset OCF2A flag by writing "1"
TIFR2 |= 1 << OCF2A;
// reset OCF0A flag by writing "1"
TIFR0 |= 1 << OCF0A;

uint8_t parity = 0xFF;

// receive other bits (including parity bit, ignore stop bits)
for (uint8_t receivedBitIndex = 0; receivedBitIndex < 9; ++receivedBitIndex) {

// wait for TCNT2 == OCR2A
// wait for TCNT0 == OCR0A
// warn: inside this loop interrupts are re-enabled to allow other libraries to work correctly (ie Servo library)
interrupts();
while (!(TIFR2 & (1 << OCF2A)))
while (!(TIFR0 & (1 << OCF0A)))
;
noInterrupts();

// reset OCF2A flag by writing "1"
TIFR2 |= 1 << OCF2A;
// reset OCF0A flag by writing "1"
TIFR0 |= 1 << OCF0A;

// sample current bit
if (pinGet(s_pin, s_pinMask))
Expand Down Expand Up @@ -272,17 +280,17 @@ void SBUS::begin(uint8_t pin, mode_t mode)
s_pinMask = pinMask(pin);
s_PCICRMask = 1 << digitalPinToPCICRbit(pin);

//// setup TIMER 2 CTC
//// setup TIMER 0 CTC

// select "Clear Timer on Compare (CTC)" mode
TCCR2A = 1 << WGM21;
TCCR0A = 1 << WGM01;

// no prescaling
TCCR2B = 1 << CS20;
TCCR0B = 1 << CS00;

// set TOP timer 2 value
// set TOP timer 0 value
// with no-prescaler 1/16000000=0.00000000625, each bit requires 10us, so reset timer 2 every 10us, so reset timer every 10/0.0625 = 160 ticks
OCR2A = F_CPU / 1000000 * 10 - 1; // for 16MHz = 159;
OCR0A = F_CPU / 1000000 * 10 - 1; // for 16MHz = 159;

//// setup pin change interrupt

Expand Down