AP_HAL & AP_HAL_AVR: new SPI driver model

This commit is contained in:
Pat Hickey 2012-11-28 17:57:20 -08:00 committed by Andrew Tridgell
parent 2a12392b9e
commit f543cede01
19 changed files with 659 additions and 330 deletions

View File

@ -12,7 +12,10 @@ namespace AP_HAL {
/* Toplevel class names for drivers: */ /* Toplevel class names for drivers: */
class UARTDriver; class UARTDriver;
class I2CDriver; class I2CDriver;
class SPIDriver;
class SPIDeviceDriver;
class SPIDeviceManager;
class AnalogSource; class AnalogSource;
class AnalogIn; class AnalogIn;
class Storage; class Storage;
@ -23,6 +26,7 @@ namespace AP_HAL {
class RCInput; class RCInput;
class RCOutput; class RCOutput;
class Scheduler; class Scheduler;
class Semaphore;
class EmptyUARTDriver; class EmptyUARTDriver;
@ -34,6 +38,20 @@ namespace AP_HAL {
/* Typdefs for function pointers (Procedure, Timed Procedure) */ /* Typdefs for function pointers (Procedure, Timed Procedure) */
typedef void(*Proc)(void); typedef void(*Proc)(void);
typedef void(*TimedProc)(uint32_t); typedef void(*TimedProc)(uint32_t);
/**
* Global names for all of the existing SPI devices on all platforms.
*/
enum SPIDevice {
SPIDevice_Dataflash,
SPIDevice_ADS7844,
SPIDevice_MS5611,
SPIDevice_MPU6000,
SPIDevice_ADNS3080_SPI0,
SPIDevice_ADNS3080_SPI3
};
} }

View File

@ -21,7 +21,7 @@ public:
AP_HAL::UARTDriver* _uart2, AP_HAL::UARTDriver* _uart2,
AP_HAL::UARTDriver* _uart3, AP_HAL::UARTDriver* _uart3,
AP_HAL::I2CDriver* _i2c, AP_HAL::I2CDriver* _i2c,
AP_HAL::SPIDriver* _spi, AP_HAL::SPIDeviceManager* _spi,
AP_HAL::AnalogIn* _analogin, AP_HAL::AnalogIn* _analogin,
AP_HAL::Storage* _storage, AP_HAL::Storage* _storage,
AP_HAL::Dataflash* _dataflash, AP_HAL::Dataflash* _dataflash,
@ -54,7 +54,7 @@ public:
AP_HAL::UARTDriver* uart2; AP_HAL::UARTDriver* uart2;
AP_HAL::UARTDriver* uart3; AP_HAL::UARTDriver* uart3;
AP_HAL::I2CDriver* i2c; AP_HAL::I2CDriver* i2c;
AP_HAL::SPIDriver* spi; AP_HAL::SPIDeviceManager* spi;
AP_HAL::AnalogIn* analogin; AP_HAL::AnalogIn* analogin;
AP_HAL::Storage* storage; AP_HAL::Storage* storage;
AP_HAL::Dataflash* dataflash; AP_HAL::Dataflash* dataflash;

View File

@ -4,18 +4,24 @@
#include "AP_HAL_Namespace.h" #include "AP_HAL_Namespace.h"
class AP_HAL::SPIDeviceManager {
public:
virtual void init(void *) = 0;
virtual SPIDeviceDriver* device(enum AP_HAL::SPIDevice) = 0;
};
/** /**
* A simple SPIDriver interface directly copied from Arduino SPI driver. * We still need an abstraction for performing bulk
* This will not be the final AP_HAL interface.
* We will need an abstraction for selecting slave devices and performing bulk
* transfers to be portable to other platforms. * transfers to be portable to other platforms.
*/ */
class AP_HAL::SPIDriver { class AP_HAL::SPIDeviceDriver {
public: public:
SPIDriver() {} virtual void init() = 0;
virtual void init(void *) = 0; virtual AP_HAL::Semaphore* get_semaphore() = 0;
virtual void set_freq(uint32_t freq_hz) = 0; virtual void cs_assert() = 0;
virtual void cs_release() = 0;
virtual uint8_t transfer (uint8_t data) = 0; virtual uint8_t transfer (uint8_t data) = 0;
}; };

View File

@ -31,8 +31,8 @@ static AVRUARTDriverInstance(avrUart3Driver, 3);
static EmptyUARTDriver emptyUartDriver; static EmptyUARTDriver emptyUartDriver;
static AVRI2CDriver avrI2CDriver; static AVRI2CDriver avrI2CDriver;
static ArduinoSPIDriver arduinoSPIDriver; static APM1SPIDeviceManager apm1SPIDriver;
static APM1SPIDriver apm1SPIDriver; static APM2SPIDeviceManager apm2SPIDriver;
static AVRAnalogIn avrAnalogIn; static AVRAnalogIn avrAnalogIn;
static AVREEPROMStorage avrEEPROMStorage; static AVREEPROMStorage avrEEPROMStorage;
static APM1Dataflash apm1Dataflash; static APM1Dataflash apm1Dataflash;
@ -51,7 +51,8 @@ const HAL_AVR AP_HAL_AVR_APM1(
(UARTDriver*) &emptyUartDriver, (UARTDriver*) &emptyUartDriver,
(UARTDriver*) &avrUart3Driver, (UARTDriver*) &avrUart3Driver,
&avrI2CDriver, &avrI2CDriver,
&arduinoSPIDriver, &apm1SPIDriver,
&avrAnalogIn,
&avrEEPROMStorage, &avrEEPROMStorage,
&apm1Dataflash, &apm1Dataflash,
&consoleDriver, &consoleDriver,
@ -66,7 +67,8 @@ const HAL_AVR AP_HAL_AVR_APM2(
(UARTDriver*) &avrUart2Driver, (UARTDriver*) &avrUart2Driver,
(UARTDriver*) &emptyUartDriver, (UARTDriver*) &emptyUartDriver,
&avrI2CDriver, &avrI2CDriver,
&arduinoSPIDriver, &apm2SPIDriver,
&avrAnalogIn,
&avrEEPROMStorage, &avrEEPROMStorage,
&apm2Dataflash, &apm2Dataflash,
&consoleDriver, &consoleDriver,

View File

@ -7,7 +7,11 @@ namespace AP_HAL_AVR {
class AVRUARTDriver; class AVRUARTDriver;
class AVRI2CDriver; class AVRI2CDriver;
class ArduinoSPIDriver; class APM1SPIDeviceManager;
class APM2SPIDeviceManager;
class AVRSPI0DeviceDriver;
class AVRSPI2DeviceDriver;
class AVRSPI3DeviceDriver;
class ADCSource; class ADCSource;
class AVRAnalogIn; class AVRAnalogIn;
class AVREEPROMStorage; class AVREEPROMStorage;
@ -15,13 +19,14 @@ namespace AP_HAL_AVR {
class APM1Dataflash; class APM1Dataflash;
class APM2Dataflash; class APM2Dataflash;
class AVRConsoleDriver; class AVRConsoleDriver;
class ArduinoGPIO; class AVRGPIO;
class ArduinoDigitalSource; class AVRDigitalSource;
class APM1RCInput; class APM1RCInput;
class APM2RCInput; class APM2RCInput;
class APM1RCOutput; class APM1RCOutput;
class APM2RCOutput; class APM2RCOutput;
class ArduinoScheduler; class AVRScheduler;
class AVRSemaphore;
class ISRRegistry; class ISRRegistry;
} }

View File

@ -89,7 +89,7 @@ protected:
*/ */
class AP_HAL_AVR::APM1Dataflash : public AP_HAL_AVR::CommonDataflash { class AP_HAL_AVR::APM1Dataflash : public AP_HAL_AVR::CommonDataflash {
public: public:
void init(void* machtnichts); void init(void* spiDevice);
void read_mfg_id(); void read_mfg_id();
bool media_present(); bool media_present();
private: private:
@ -108,13 +108,12 @@ private:
uint8_t _read_status_reg(); uint8_t _read_status_reg();
uint8_t _read_status(); uint8_t _read_status();
void _cs_active(); AP_HAL::SPIDeviceDriver *_spi;
void _cs_inactive();
}; };
class AP_HAL_AVR::APM2Dataflash : public AP_HAL_AVR::CommonDataflash { class AP_HAL_AVR::APM2Dataflash : public AP_HAL_AVR::CommonDataflash {
public: public:
void init(void* machtnichts); void init(void* spiDevice);
void read_mfg_id(); void read_mfg_id();
bool media_present(); bool media_present();
private: private:
@ -133,9 +132,7 @@ private:
uint8_t _read_status_reg(); uint8_t _read_status_reg();
uint8_t _read_status(); uint8_t _read_status();
void _cs_active(); AP_HAL::SPIDeviceDriver *_spi;
void _cs_inactive();
uint8_t _transfer(uint8_t data);
}; };
#endif // __AP_HAL_AVR_DATAFLASH_H__ #endif // __AP_HAL_AVR_DATAFLASH_H__

View File

@ -8,12 +8,7 @@ extern const AP_HAL::HAL& hal;
/* flash size */ /* flash size */
#define DF_LAST_PAGE 4096 #define DF_LAST_PAGE 4096
/* Arduino Mega SPI pins */ #define DF_RESET_PIN 31 /* (PC6) */
#define DF_DATAOUT 51 /* MOSI */
#define DF_DATAIN 50 /* MISO */
#define DF_SPICLOCK 52 /* SCK */
#define DF_SLAVESELECT 53 /* SS (PB0) */
#define DF_RESET 31 /* RESET (PC6) */
/* AT45DB161D commands (from datasheet) */ /* AT45DB161D commands (from datasheet) */
#define DF_TRANSFER_PAGE_TO_BUFFER_1 0x53 #define DF_TRANSFER_PAGE_TO_BUFFER_1 0x53
@ -37,20 +32,14 @@ extern const AP_HAL::HAL& hal;
void APM1Dataflash::init(void* machtnichts) { void APM1Dataflash::init(void* machtnichts) {
hal.gpio->pinMode(DF_DATAOUT, GPIO_OUTPUT); hal.gpio->pinMode(DF_RESET_PIN, GPIO_OUTPUT);
hal.gpio->pinMode(DF_DATAIN , GPIO_INPUT);
hal.gpio->pinMode(DF_SPICLOCK, GPIO_OUTPUT);
hal.gpio->pinMode(DF_SLAVESELECT, GPIO_OUTPUT);
hal.gpio->pinMode(DF_RESET, GPIO_OUTPUT);
/* Reset the dataflash chip */ /* Reset the dataflash chip */
hal.gpio->write(DF_RESET, 0); hal.gpio->write(DF_RESET_PIN, 0);
hal.scheduler->delay(1); hal.scheduler->delay(1);
hal.gpio->write(DF_RESET, 1); hal.gpio->write(DF_RESET_PIN, 1);
_cs_inactive(); _spi = hal.spi->device(AP_HAL::SPIDevice_Dataflash);
hal.spi->set_freq(8000000L);
_num_pages = DF_LAST_PAGE - 1; _num_pages = DF_LAST_PAGE - 1;
uint8_t status = _read_status_reg(); uint8_t status = _read_status_reg();
@ -58,14 +47,14 @@ void APM1Dataflash::init(void* machtnichts) {
} }
void APM1Dataflash::read_mfg_id() { void APM1Dataflash::read_mfg_id() {
_cs_active(); _spi->cs_assert();
hal.spi->transfer(DF_READ_MANUFACTURER_AND_DEVICE_ID); _spi->transfer(DF_READ_MANUFACTURER_AND_DEVICE_ID);
_mfg = hal.spi->transfer(0xFF); _mfg = _spi->transfer(0xFF);
_device = hal.spi->transfer(0xFF); _device = _spi->transfer(0xFF);
_device = (_device << 8) | hal.spi->transfer(0xFF); _device = (_device << 8) | _spi->transfer(0xFF);
/* fourth byte is dont care */ /* fourth byte is dont care */
hal.spi->transfer(0xFF); _spi->transfer(0xFF);
_cs_inactive(); _spi->cs_release();
} }
bool APM1Dataflash::media_present() { bool APM1Dataflash::media_present() {
@ -77,93 +66,93 @@ void APM1Dataflash::_wait_ready() {
} }
void APM1Dataflash::_page_to_buffer(uint8_t buffer_num, uint16_t page_addr) { void APM1Dataflash::_page_to_buffer(uint8_t buffer_num, uint16_t page_addr) {
_cs_active(); _spi->cs_assert();
if (_buffer_num == 1) { if (_buffer_num == 1) {
hal.spi->transfer(DF_TRANSFER_PAGE_TO_BUFFER_1); _spi->transfer(DF_TRANSFER_PAGE_TO_BUFFER_1);
} else { } else {
hal.spi->transfer(DF_TRANSFER_PAGE_TO_BUFFER_2); _spi->transfer(DF_TRANSFER_PAGE_TO_BUFFER_2);
} }
if (_page_size == 512) { if (_page_size == 512) {
hal.spi->transfer( page_addr >> 7 ); _spi->transfer( page_addr >> 7 );
hal.spi->transfer( page_addr << 1 ); _spi->transfer( page_addr << 1 );
} else { } else {
hal.spi->transfer( page_addr >> 6 ); _spi->transfer( page_addr >> 6 );
hal.spi->transfer( page_addr << 2 ); _spi->transfer( page_addr << 2 );
} }
/* finally send one dont care byte */ /* finally send one dont care byte */
hal.spi->transfer(0x00); _spi->transfer(0x00);
_cs_inactive(); _spi->cs_release();
_wait_ready(); _wait_ready();
} }
void APM1Dataflash::_buffer_to_page(uint8_t buffer_num, uint16_t page_addr, bool wait) { void APM1Dataflash::_buffer_to_page(uint8_t buffer_num, uint16_t page_addr, bool wait) {
_cs_active(); _spi->cs_assert();
if (_buffer_num == 1) { if (_buffer_num == 1) {
hal.spi->transfer(DF_BUFFER_1_TO_PAGE_WITH_ERASE); _spi->transfer(DF_BUFFER_1_TO_PAGE_WITH_ERASE);
} else { } else {
hal.spi->transfer(DF_BUFFER_2_TO_PAGE_WITH_ERASE); _spi->transfer(DF_BUFFER_2_TO_PAGE_WITH_ERASE);
} }
if (_page_size == 512) { if (_page_size == 512) {
hal.spi->transfer( page_addr >> 7 ); _spi->transfer( page_addr >> 7 );
hal.spi->transfer( page_addr << 1 ); _spi->transfer( page_addr << 1 );
} else { } else {
hal.spi->transfer( page_addr >> 6 ); _spi->transfer( page_addr >> 6 );
hal.spi->transfer( page_addr << 2 ); _spi->transfer( page_addr << 2 );
} }
/* finally send one dont care byte */ /* finally send one dont care byte */
hal.spi->transfer(0x00); _spi->transfer(0x00);
_cs_inactive(); _spi->cs_release();
if (wait) { if (wait) {
_wait_ready(); _wait_ready();
} }
} }
void APM1Dataflash::_page_erase(uint16_t page_addr) { void APM1Dataflash::_page_erase(uint16_t page_addr) {
_cs_active(); _spi->cs_assert();
hal.spi->transfer(DF_PAGE_ERASE); _spi->transfer(DF_PAGE_ERASE);
if (_page_size == 512) { if (_page_size == 512) {
hal.spi->transfer( page_addr >> 7 ); _spi->transfer( page_addr >> 7 );
hal.spi->transfer( page_addr << 1 ); _spi->transfer( page_addr << 1 );
} else { } else {
hal.spi->transfer( page_addr >> 6 ); _spi->transfer( page_addr >> 6 );
hal.spi->transfer( page_addr << 2 ); _spi->transfer( page_addr << 2 );
} }
/* finally send one dont care byte */ /* finally send one dont care byte */
hal.spi->transfer(0x00); _spi->transfer(0x00);
_cs_inactive(); _spi->cs_release();
_wait_ready(); _wait_ready();
} }
void APM1Dataflash::_block_erase(uint16_t block_addr) { void APM1Dataflash::_block_erase(uint16_t block_addr) {
_cs_active(); _spi->cs_assert();
hal.spi->transfer(DF_BLOCK_ERASE); _spi->transfer(DF_BLOCK_ERASE);
if (_page_size == 512) { if (_page_size == 512) {
hal.spi->transfer( block_addr >> 7 ); _spi->transfer( block_addr >> 7 );
hal.spi->transfer( block_addr << 1 ); _spi->transfer( block_addr << 1 );
} else { } else {
hal.spi->transfer( block_addr >> 6 ); _spi->transfer( block_addr >> 6 );
hal.spi->transfer( block_addr << 2 ); _spi->transfer( block_addr << 2 );
} }
/* finally send one dont care byte */ /* finally send one dont care byte */
hal.spi->transfer(0x00); _spi->transfer(0x00);
_cs_inactive(); _spi->cs_release();
_wait_ready(); _wait_ready();
} }
void APM1Dataflash::_chip_erase() { void APM1Dataflash::_chip_erase() {
_cs_active(); _spi->cs_assert();
hal.spi->transfer(DF_CHIP_ERASE_0); _spi->transfer(DF_CHIP_ERASE_0);
hal.spi->transfer(DF_CHIP_ERASE_1); _spi->transfer(DF_CHIP_ERASE_1);
hal.spi->transfer(DF_CHIP_ERASE_2); _spi->transfer(DF_CHIP_ERASE_2);
hal.spi->transfer(DF_CHIP_ERASE_3); _spi->transfer(DF_CHIP_ERASE_3);
_cs_inactive(); _spi->cs_release();
while(!_read_status()) { while(!_read_status()) {
hal.scheduler->delay(1); hal.scheduler->delay(1);
@ -171,48 +160,48 @@ void APM1Dataflash::_chip_erase() {
} }
void APM1Dataflash::_buffer_write(uint8_t buffer_num, uint16_t page_addr, uint8_t data) { void APM1Dataflash::_buffer_write(uint8_t buffer_num, uint16_t page_addr, uint8_t data) {
_cs_active(); _spi->cs_assert();
if (buffer_num == 1) { if (buffer_num == 1) {
hal.spi->transfer(DF_BUFFER_1_WRITE); _spi->transfer(DF_BUFFER_1_WRITE);
} else { } else {
hal.spi->transfer(DF_BUFFER_2_WRITE); _spi->transfer(DF_BUFFER_2_WRITE);
} }
/* Don't care */ /* Don't care */
hal.spi->transfer(0); _spi->transfer(0);
/* Internal buffer address */ /* Internal buffer address */
hal.spi->transfer((uint8_t)(page_addr >> 8)); _spi->transfer((uint8_t)(page_addr >> 8));
hal.spi->transfer((uint8_t)(page_addr & 0xFF)); _spi->transfer((uint8_t)(page_addr & 0xFF));
/* Byte to write */ /* Byte to write */
hal.spi->transfer(data); _spi->transfer(data);
_cs_inactive(); _spi->cs_release();
} }
uint8_t APM1Dataflash::_buffer_read(uint8_t buffer_num, uint16_t page_addr) { uint8_t APM1Dataflash::_buffer_read(uint8_t buffer_num, uint16_t page_addr) {
_cs_active(); _spi->cs_assert();
if (buffer_num == 1) { if (buffer_num == 1) {
hal.spi->transfer(DF_BUFFER_1_READ); _spi->transfer(DF_BUFFER_1_READ);
} else { } else {
hal.spi->transfer(DF_BUFFER_2_READ); _spi->transfer(DF_BUFFER_2_READ);
} }
/* Don't care */ /* Don't care */
hal.spi->transfer(0); _spi->transfer(0);
/* Internal buffer address */ /* Internal buffer address */
hal.spi->transfer((uint8_t)(page_addr >> 8)); _spi->transfer((uint8_t)(page_addr >> 8));
hal.spi->transfer((uint8_t)(page_addr & 0xFF)); _spi->transfer((uint8_t)(page_addr & 0xFF));
/* Don't care */ /* Don't care */
hal.spi->transfer(0); _spi->transfer(0);
/* Read data byte */ /* Read data byte */
uint8_t res = hal.spi->transfer(0); uint8_t res = _spi->transfer(0);
_cs_inactive(); _spi->cs_release();
return res; return res;
} }
inline uint8_t APM1Dataflash::_read_status_reg() { inline uint8_t APM1Dataflash::_read_status_reg() {
_cs_active(); _spi->cs_assert();
hal.spi->transfer(DF_STATUS_REGISTER_READ); _spi->transfer(DF_STATUS_REGISTER_READ);
/* Read the first byte of the result */ /* Read the first byte of the result */
uint8_t res = hal.spi->transfer(0); uint8_t res = _spi->transfer(0);
_cs_inactive(); _spi->cs_release();
return res; return res;
} }
@ -221,10 +210,3 @@ inline uint8_t APM1Dataflash::_read_status() {
return _read_status_reg() & 0x80; return _read_status_reg() & 0x80;
} }
inline void APM1Dataflash::_cs_inactive() {
hal.gpio->write(DF_SLAVESELECT, 1);
}
inline void APM1Dataflash::_cs_active() {
hal.gpio->write(DF_SLAVESELECT, 0);
}

View File

@ -7,12 +7,8 @@ using namespace AP_HAL_AVR;
extern const AP_HAL::HAL& hal; extern const AP_HAL::HAL& hal;
/* Connected to USART3 in SPI mode */ /* Connected to USART3 in SPI mode */
#define DF_DATAOUT 14 /* MOSI */ #define DF_RESET_PIN 41 /* RESET (PG0) */
#define DF_DATAIN 15 /* MISO */ #define DF_CARDDETECT_PIN 33 /* PC4 */
#define DF_SPICLOCK PJ2 /* SCK (not used via gpio) */
#define DF_SLAVESELECT 28 /* SS (PA6) */
#define DF_RESET 41 /* RESET (PG0) */
#define DF_CARDDETECT 33 /* PC4 */
// AT45DB321D Commands (from Datasheet) // AT45DB321D Commands (from Datasheet)
#define DF_TRANSFER_PAGE_TO_BUFFER_1 0x53 #define DF_TRANSFER_PAGE_TO_BUFFER_1 0x53
@ -34,6 +30,8 @@ extern const AP_HAL::HAL& hal;
#define DF_CHIP_ERASE_2 0x80 #define DF_CHIP_ERASE_2 0x80
#define DF_CHIP_ERASE_3 0x9A #define DF_CHIP_ERASE_3 0x9A
#define DEBUG
#ifdef DEBUG #ifdef DEBUG
#define LOGD(format, ...) do { hal.console->printf_P(PSTR("DBG/Dataflash: "format), __VA_ARGS__); } while (0) #define LOGD(format, ...) do { hal.console->printf_P(PSTR("DBG/Dataflash: "format), __VA_ARGS__); } while (0)
#else #else
@ -43,29 +41,15 @@ extern const AP_HAL::HAL& hal;
void APM2Dataflash::init(void* machtnichts) { void APM2Dataflash::init(void* machtnichts) {
/* setup gpio pins */ /* setup gpio pins */
hal.gpio->pinMode(DF_DATAOUT, GPIO_OUTPUT); hal.gpio->pinMode(DF_RESET_PIN, GPIO_OUTPUT);
hal.gpio->pinMode(DF_DATAIN, GPIO_OUTPUT); hal.gpio->pinMode(DF_CARDDETECT_PIN, GPIO_INPUT);
hal.gpio->pinMode(DF_SLAVESELECT, GPIO_OUTPUT);
hal.gpio->pinMode(DF_RESET, GPIO_OUTPUT);
hal.gpio->pinMode(DF_CARDDETECT, GPIO_INPUT);
/* Reset device */ /* Reset device */
hal.gpio->write(DF_RESET, 0); hal.gpio->write(DF_RESET_PIN, 0);
hal.scheduler->delay(1); hal.scheduler->delay(1);
hal.gpio->write(DF_RESET, 1); hal.gpio->write(DF_RESET_PIN, 1);
_cs_inactive(); _spi = hal.spi->device(AP_HAL::SPIDevice_Dataflash);
/* Setup USART3 in SPI mode (MSPI), Mode 0, clock 8Mhz */
UBRR3 = 0;
/* DF_SPICLOCK: use XCK3 (PJ2) as output. Enables SPI master mode. */
DDRJ |= _BV(PJ2);
/* Set MSPI mode of operation and SPI data mode 0 */
UCSR3C = _BV(UMSEL31) | _BV(UMSEL30);
/* Enable transmitter and receiver */
UCSR3B = _BV(RXEN3) | _BV(TXEN3);
/* Set baud rate to 8Mhz */
UBRR3 = 0;
uint8_t status = _read_status_reg(); uint8_t status = _read_status_reg();
_page_size = (status & 0x01) ? 512 : 528; _page_size = (status & 0x01) ? 512 : 528;
@ -87,13 +71,13 @@ void APM2Dataflash::init(void* machtnichts) {
} }
void APM2Dataflash::read_mfg_id() { void APM2Dataflash::read_mfg_id() {
_cs_active(); _spi->cs_assert();
_transfer(DF_READ_MANUFACTURER_AND_DEVICE_ID); _spi->transfer(DF_READ_MANUFACTURER_AND_DEVICE_ID);
_mfg = _transfer(0xFF); _mfg = _spi->transfer(0xFF);
_device = _transfer(0xFF); _device = _spi->transfer(0xFF);
_device = (_device << 8) | _transfer(0xFF); _device = (_device << 8) | _spi->transfer(0xFF);
_transfer(0xFF); _spi->transfer(0xFF);
_cs_inactive(); _spi->cs_release();
} }
bool APM2Dataflash::media_present() { bool APM2Dataflash::media_present() {
@ -107,96 +91,96 @@ void APM2Dataflash::_wait_ready() {
void APM2Dataflash::_page_to_buffer(uint8_t buffer_num, uint16_t page_addr) { void APM2Dataflash::_page_to_buffer(uint8_t buffer_num, uint16_t page_addr) {
LOGD("_page_to_buffer: buf: %d page: %d\r\n", (int) buffer_num, page_addr); LOGD("_page_to_buffer: buf: %d page: %d\r\n", (int) buffer_num, page_addr);
_cs_active(); _spi->cs_assert();
if (_buffer_num == 1) { if (_buffer_num == 1) {
_transfer(DF_TRANSFER_PAGE_TO_BUFFER_1); _spi->transfer(DF_TRANSFER_PAGE_TO_BUFFER_1);
} else { } else {
_transfer(DF_TRANSFER_PAGE_TO_BUFFER_2); _spi->transfer(DF_TRANSFER_PAGE_TO_BUFFER_2);
} }
if (_page_size == 512) { if (_page_size == 512) {
_transfer((uint8_t)(page_addr >> 7)); _spi->transfer((uint8_t)(page_addr >> 7));
_transfer((uint8_t)(page_addr << 1)); _spi->transfer((uint8_t)(page_addr << 1));
} else { } else {
_transfer((uint8_t)(page_addr >> 6)); _spi->transfer((uint8_t)(page_addr >> 6));
_transfer((uint8_t)(page_addr << 2)); _spi->transfer((uint8_t)(page_addr << 2));
} }
/* finally send one dont care byte */ /* finally send one dont care byte */
_transfer(0x00); _spi->transfer(0x00);
_cs_inactive(); _spi->cs_release();
_wait_ready(); _wait_ready();
} }
void APM2Dataflash::_buffer_to_page(uint8_t buffer_num, uint16_t page_addr, bool wait) { void APM2Dataflash::_buffer_to_page(uint8_t buffer_num, uint16_t page_addr, bool wait) {
LOGD("_buffer_to_page buf: %d, page: %d\r\n", LOGD("_buffer_to_page buf: %d, page: %d\r\n",
(int) buffer_num, page_addr); (int) buffer_num, page_addr);
_cs_active(); _spi->cs_assert();
if (_buffer_num == 1) { if (_buffer_num == 1) {
_transfer(DF_BUFFER_1_TO_PAGE_WITH_ERASE); _spi->transfer(DF_BUFFER_1_TO_PAGE_WITH_ERASE);
} else { } else {
_transfer(DF_BUFFER_2_TO_PAGE_WITH_ERASE); _spi->transfer(DF_BUFFER_2_TO_PAGE_WITH_ERASE);
} }
if (_page_size == 512) { if (_page_size == 512) {
_transfer((uint8_t)(page_addr >> 7)); _spi->transfer((uint8_t)(page_addr >> 7));
_transfer((uint8_t)(page_addr << 1)); _spi->transfer((uint8_t)(page_addr << 1));
} else { } else {
_transfer((uint8_t)(page_addr >> 6)); _spi->transfer((uint8_t)(page_addr >> 6));
_transfer((uint8_t)(page_addr << 2)); _spi->transfer((uint8_t)(page_addr << 2));
} }
/* finally send one dont care byte */ /* finally send one dont care byte */
_transfer(0x00); _spi->transfer(0x00);
_cs_inactive(); _spi->cs_release();
if (wait) { if (wait) {
_wait_ready(); _wait_ready();
} }
} }
void APM2Dataflash::_page_erase(uint16_t page_addr) { void APM2Dataflash::_page_erase(uint16_t page_addr) {
_cs_active(); _spi->cs_assert();
_transfer(DF_PAGE_ERASE); _spi->transfer(DF_PAGE_ERASE);
if (_page_size == 512) { if (_page_size == 512) {
_transfer( page_addr >> 7 ); _spi->transfer( page_addr >> 7 );
_transfer( page_addr << 1 ); _spi->transfer( page_addr << 1 );
} else { } else {
_transfer( page_addr >> 6 ); _spi->transfer( page_addr >> 6 );
_transfer( page_addr << 2 ); _spi->transfer( page_addr << 2 );
} }
/* finally send one dont care byte */ /* finally send one dont care byte */
_transfer(0x00); _spi->transfer(0x00);
_cs_inactive(); _spi->cs_release();
_wait_ready(); _wait_ready();
} }
void APM2Dataflash::_block_erase(uint16_t block_addr) { void APM2Dataflash::_block_erase(uint16_t block_addr) {
LOGD("_block_erase %d\r\n", block_addr); LOGD("_block_erase %d\r\n", block_addr);
_cs_active(); _spi->cs_assert();
_transfer(DF_BLOCK_ERASE); _spi->transfer(DF_BLOCK_ERASE);
if (_page_size == 512) { if (_page_size == 512) {
_transfer( block_addr >> 7 ); _spi->transfer( block_addr >> 7 );
_transfer( block_addr << 1 ); _spi->transfer( block_addr << 1 );
} else { } else {
_transfer( block_addr >> 6 ); _spi->transfer( block_addr >> 6 );
_transfer( block_addr << 2 ); _spi->transfer( block_addr << 2 );
} }
/* finally send one dont care byte */ /* finally send one dont care byte */
_transfer(0x00); _spi->transfer(0x00);
_cs_inactive(); _spi->cs_release();
_wait_ready(); _wait_ready();
} }
void APM2Dataflash::_chip_erase() { void APM2Dataflash::_chip_erase() {
_cs_active(); _spi->cs_assert();
_transfer(DF_CHIP_ERASE_0); _spi->transfer(DF_CHIP_ERASE_0);
_transfer(DF_CHIP_ERASE_1); _spi->transfer(DF_CHIP_ERASE_1);
_transfer(DF_CHIP_ERASE_2); _spi->transfer(DF_CHIP_ERASE_2);
_transfer(DF_CHIP_ERASE_3); _spi->transfer(DF_CHIP_ERASE_3);
_cs_inactive(); _spi->cs_release();
while(!_read_status()) { while(!_read_status()) {
hal.scheduler->delay(1); hal.scheduler->delay(1);
@ -206,50 +190,50 @@ void APM2Dataflash::_chip_erase() {
void APM2Dataflash::_buffer_write(uint8_t buffer_num, uint16_t page_addr, uint8_t data) { void APM2Dataflash::_buffer_write(uint8_t buffer_num, uint16_t page_addr, uint8_t data) {
LOGD("_buffer_write buf: %d page: %d data: %d\r\n", LOGD("_buffer_write buf: %d page: %d data: %d\r\n",
(int) buffer_num, page_addr, (int) data); (int) buffer_num, page_addr, (int) data);
_cs_active(); _spi->cs_assert();
if (buffer_num == 1) { if (buffer_num == 1) {
_transfer(DF_BUFFER_1_WRITE); _spi->transfer(DF_BUFFER_1_WRITE);
} else { } else {
_transfer(DF_BUFFER_2_WRITE); _spi->transfer(DF_BUFFER_2_WRITE);
} }
/* Don't care */ /* Don't care */
_transfer(0); _spi->transfer(0);
/* Internal buffer address */ /* Internal buffer address */
_transfer((uint8_t)(page_addr >> 8)); _spi->transfer((uint8_t)(page_addr >> 8));
_transfer((uint8_t)(page_addr & 0xFF)); _spi->transfer((uint8_t)(page_addr & 0xFF));
/* Byte to write */ /* Byte to write */
_transfer(data); _spi->transfer(data);
_cs_inactive(); _spi->cs_release();
} }
uint8_t APM2Dataflash::_buffer_read(uint8_t buffer_num, uint16_t page_addr) { uint8_t APM2Dataflash::_buffer_read(uint8_t buffer_num, uint16_t page_addr) {
_cs_active(); _spi->cs_assert();
if (buffer_num == 1) { if (buffer_num == 1) {
_transfer(DF_BUFFER_1_READ); _spi->transfer(DF_BUFFER_1_READ);
} else { } else {
_transfer(DF_BUFFER_2_READ); _spi->transfer(DF_BUFFER_2_READ);
} }
/* Don't care */ /* Don't care */
_transfer(0); _spi->transfer(0);
/* Internal buffer address */ /* Internal buffer address */
_transfer((uint8_t)(page_addr >> 8)); _spi->transfer((uint8_t)(page_addr >> 8));
_transfer((uint8_t)(page_addr & 0xFF)); _spi->transfer((uint8_t)(page_addr & 0xFF));
/* Don't care */ /* Don't care */
_transfer(0); _spi->transfer(0);
/* Read data byte */ /* Read data byte */
uint8_t res = _transfer(0); uint8_t res = _spi->transfer(0);
_cs_inactive(); _spi->cs_release();
LOGD("_buffer_read num: %d pageaddr: %d result: %d\r\n", LOGD("_buffer_read num: %d pageaddr: %d result: %d\r\n",
(int) buffer_num, (int) page_addr, (int) res); (int) buffer_num, (int) page_addr, (int) res);
return res; return res;
} }
inline uint8_t APM2Dataflash::_read_status_reg() { inline uint8_t APM2Dataflash::_read_status_reg() {
_cs_active(); _spi->cs_assert();
_transfer(DF_STATUS_REGISTER_READ); _spi->transfer(DF_STATUS_REGISTER_READ);
/* Read the first byte of the result */ /* Read the first byte of the result */
uint8_t res = _transfer(0); uint8_t res = _spi->transfer(0);
_cs_inactive(); _spi->cs_release();
return res; return res;
} }
@ -258,23 +242,3 @@ inline uint8_t APM2Dataflash::_read_status() {
return _read_status_reg() & 0x80; return _read_status_reg() & 0x80;
} }
inline void APM2Dataflash::_cs_inactive() {
hal.gpio->write(DF_SLAVESELECT, 1);
}
inline void APM2Dataflash::_cs_active() {
hal.gpio->write(DF_SLAVESELECT, 0);
}
/* APM2 uses USART3 in SPI mode to talk to the dataflash */
inline uint8_t APM2Dataflash::_transfer(uint8_t data) {
/* Wait for empty transmit buffer */
while (!(UCSR3A & _BV(UDRE3)));
/* Put data into buffer to start sending */
UDR3 = data;
/* Wait for receive buffer to be full */
while (!(UCSR3A & _BV(RXC3)));
/* Return received data */
return UDR3;
}

View File

@ -19,7 +19,7 @@ public:
AP_HAL::UARTDriver* _uart2, AP_HAL::UARTDriver* _uart2,
AP_HAL::UARTDriver* _uart3, AP_HAL::UARTDriver* _uart3,
AP_HAL::I2CDriver* _i2c, AP_HAL::I2CDriver* _i2c,
AP_HAL::SPIDriver* _spi, AP_HAL::SPIDeviceManager* _spi,
AP_HAL::AnalogIn* _analogin, AP_HAL::AnalogIn* _analogin,
AP_HAL::Storage* _storage, AP_HAL::Storage* _storage,
AP_HAL::Dataflash* _dataflash, AP_HAL::Dataflash* _dataflash,

View File

@ -0,0 +1,49 @@
#include <avr/io.h>
#include <AP_HAL.h>
#include "SPIDriver.h"
#include "SPIDevices.h"
#include "GPIO.h"
#include "pins_arduino_mega.h"
using namespace AP_HAL_AVR;
extern const AP_HAL::HAL& hal;
void APM1SPIDeviceManager::init(void* machtnichts) {
/* dataflow cs is on arduino pin 53, PORTB0 */
AVRDigitalSource* df_cs = new AVRDigitalSource(_BV(0), PB);
/* dataflash: divide clock by 2 to 8Mhz, set SPI_MODE_3
* spcr gets 0x0C to set SPI_MODE_3
* spsr gets bit SPI2X for clock divider */
_dataflash = new AVRSPI0DeviceDriver(df_cs, 0x0C, _BV(SPI2X));
_dataflash->init();
/* optflow cs is on Arduino pin 34, PORTC3 */
AVRDigitalSource* opt_cs = new AVRDigitalSource(_BV(3), PC);
/* optflow: divide clock by 8 to 2Mhz
* spcr gets bit SPR0, spsr gets bit SPI2X */
_optflow = new AVRSPI0DeviceDriver(opt_cs, _BV(SPR0), 0);
_optflow->init();
/* adc cs is on Arduino pin 33, PORTC4 */
AVRDigitalSource* adc_cs = new AVRDigitalSource(_BV(4), PC);
/* adc: ubbr2 gets value of 2 to run at 2.6Mhz
* (config value cribbed from AP_ADC_ADS7844 driver pre-port) */
_adc = new AVRSPI2DeviceDriver(adc_cs, 0, 2);
_adc->init();
}
AP_HAL::SPIDeviceDriver* APM1SPIDeviceManager::device(enum AP_HAL::SPIDevice d)
{
switch (d) {
case AP_HAL::SPIDevice_Dataflash:
return _dataflash;
case AP_HAL::SPIDevice_ADS7844:
return _adc;
case AP_HAL::SPIDevice_ADNS3080_SPI0:
return _optflow;
default:
return NULL;
};
}

View File

@ -0,0 +1,64 @@
#include <avr/io.h>
#include <AP_HAL.h>
#include "SPIDriver.h"
#include "SPIDevices.h"
#include "pins_arduino_mega.h"
using namespace AP_HAL_AVR;
extern const AP_HAL::HAL& hal;
void APM2SPIDeviceManager::init(void* machtnichts) {
/* ms5611 cs is on Arduino pin 40, PORTG1 */
AVRDigitalSource* ms5611_cs = new AVRDigitalSource(_BV(1), PG);
/* ms5611: divide clock by 32 to 500khz
* spcr gets bit SPR1, spsr gets bit SPI2X */
_ms5611 = new AVRSPI0DeviceDriver(ms5611_cs, _BV(SPR1), _BV(SPI2X));
_ms5611->init();
/* ms5611 cs is on Arduino pin 53, PORTB0 */
AVRDigitalSource* mpu6k_cs = new AVRDigitalSource(_BV(0), PB);
/* mpu6k: divide clock by 32 to 500khz
* spcr gets bit SPR1, spsr gets bit SPI2X */
_mpu6k = new AVRSPI0DeviceDriver(mpu6k_cs, _BV(SPR1), _BV(SPI2X));
_mpu6k->init();
/* optflow cs is on Arduino pin A3, PORTF3 */
AVRDigitalSource* optflow_cs = new AVRDigitalSource(_BV(3), PF);
/* optflow: divide clock by 8 to 2Mhz
* spcr gets bit SPR0, spsr gets bit SPI2X */
_optflow_spi0 = new AVRSPI0DeviceDriver(optflow_cs, _BV(SPR0), _BV(SPI2X));
_optflow_spi0->init();
/* Dataflash CS is on Arduino pin 28, PORTA6 */
AVRDigitalSource* df_cs = new AVRDigitalSource(_BV(6), PA);
/* dataflash uses mode 0 and a clock of 8mhz
* ucsr3c = 0
* ubrr3 = 0 */
_dataflash = new AVRSPI3DeviceDriver(df_cs, 0, 0);
_dataflash->init();
/* XXX need correct mode and baud */
_optflow_spi3 = new AVRSPI3DeviceDriver(optflow_cs, 0, 0);
_optflow_spi3->init();
}
AP_HAL::SPIDeviceDriver* APM2SPIDeviceManager::device(enum AP_HAL::SPIDevice d)
{
switch (d) {
case AP_HAL::SPIDevice_Dataflash:
return _dataflash;
case AP_HAL::SPIDevice_MS5611:
return _ms5611;
case AP_HAL::SPIDevice_MPU6000:
return _mpu6k;
case AP_HAL::SPIDevice_ADNS3080_SPI0:
return _optflow_spi0;
case AP_HAL::SPIDevice_ADNS3080_SPI3:
return _optflow_spi3;
default:
return NULL;
};
}

View File

@ -0,0 +1,61 @@
#include <avr/io.h>
#include <AP_HAL.h>
#include "SPIDevices.h"
#include "GPIO.h"
#include "Semaphore.h"
#include "pins_arduino_mega.h"
using namespace AP_HAL_AVR;
extern const AP_HAL::HAL& hal;
#define SPI0_MISO_PIN 50
#define SPI0_MOSI_PIN 51
#define SPI0_SCK_PIN 52
AVRSemaphore AVRSPI0DeviceDriver::_semaphore;
void AVRSPI0DeviceDriver::init() {
hal.gpio->pinMode(SPI0_MISO_PIN, GPIO_INPUT);
hal.gpio->pinMode(SPI0_MOSI_PIN, GPIO_OUTPUT);
hal.gpio->pinMode(SPI0_SCK_PIN, GPIO_OUTPUT);
_cs_pin->mode(GPIO_OUTPUT);
_cs_pin->write(1);
/* Enable the SPI0 peripheral as a master */
SPCR = _BV(SPE) | _BV(MSTR);
}
AP_HAL::Semaphore* AVRSPI0DeviceDriver::get_semaphore() {
return &_semaphore;
}
void AVRSPI0DeviceDriver::cs_assert() {
const uint8_t valid_spcr_mask =
(_BV(CPOL) | _BV(CPHA) | _BV(SPR1) | _BV(SPR0));
uint8_t new_spcr = SPCR | (_spcr & valid_spcr_mask);
SPCR = new_spcr;
const uint8_t valid_spsr_mask = _BV(SPI2X);
uint8_t new_spsr = SPSR | (_spsr & valid_spsr_mask);
SPSR = new_spsr;
_cs_pin->write(0);
}
void AVRSPI0DeviceDriver::cs_release() {
_cs_pin->write(1);
}
uint8_t AVRSPI0DeviceDriver::transfer(uint8_t data) {
SPDR = data;
if (SPSR & _BV(WCOL)) {
hal.console->println_P(PSTR("PANIC: SPI0 write collision"));
return 0;
}
while(!(SPSR & _BV(SPIF)));
return SPDR;
}

View File

@ -0,0 +1,69 @@
#include <avr/io.h>
#include <AP_HAL.h>
#include "SPIDevices.h"
#include "GPIO.h"
#include "Semaphore.h"
#include "pins_arduino_mega.h"
using namespace AP_HAL_AVR;
extern const AP_HAL::HAL& hal;
AVRSemaphore AVRSPI2DeviceDriver::_semaphore;
void AVRSPI2DeviceDriver::init() {
AVRDigitalSource spi2_miso(_BV(0), PH);
spi2_miso.mode(GPIO_INPUT);
AVRDigitalSource spi2_mosi(_BV(1), PH);
spi2_mosi.mode(GPIO_OUTPUT);
AVRDigitalSource spi2_sck(_BV(2), PH);
spi2_sck.mode(GPIO_OUTPUT);
/* UMSELn1 and UMSELn2: USART in SPI Master mode */
UCSR2C = _BV(UMSEL21) | _BV(UMSEL20);
/* Enable RX and TX. */
UCSR2B = _BV(RXEN2) | _BV(TXEN2);
/* Setup chip select pin */
_cs_pin->mode(GPIO_OUTPUT);
_cs_pin->write(1);
}
AP_HAL::Semaphore* AVRSPI2DeviceDriver::get_semaphore() {
return &_semaphore;
}
void AVRSPI2DeviceDriver::cs_assert() {
/* set the device UCSRnC configuration bits.
* only sets data order, clock phase, and clock polarity bits (lowest
* three bits) */
const uint8_t new_ucsr2c = UCSR2C | (_ucsr2c & (0x07));
UCSR2C = new_ucsr2c;
/* set the device baud rate */
UBRR2 = _ubrr2;
_cs_pin->write(0);
}
void AVRSPI2DeviceDriver::cs_release() {
_cs_pin->write(1);
}
uint8_t AVRSPI2DeviceDriver::transfer(uint8_t data) {
/* Wait for empty transmit buffer */
while ( !( UCSR2A & _BV(UDRE2)) ) ;
/* Put data into buffer, sends the data */
UDR2 = data;
/* Wait for data to be received */
while ( !(UCSR2A & _BV(RXC2)) ) ;
/* Get and return received data from buffer */
return UDR2;
}

View File

@ -0,0 +1,73 @@
#include <avr/io.h>
#include <AP_HAL.h>
#include "SPIDevices.h"
#include "GPIO.h"
#include "Semaphore.h"
#include "pins_arduino_mega.h"
using namespace AP_HAL_AVR;
#define SPI3_MOSI 14
#define SPI3_MISO 15
extern const AP_HAL::HAL& hal;
AVRSemaphore AVRSPI3DeviceDriver::_semaphore;
void AVRSPI3DeviceDriver::init() {
/* the spi3 (USART3) sck pin PORTJ2 is not enumerated
* by the arduino pin numbers, so we access it directly
* with AVRDigitalSource. */
AVRDigitalSource spi3_sck(_BV(2), PJ);
spi3_sck.mode(GPIO_OUTPUT);
hal.gpio->pinMode(SPI3_MOSI, GPIO_OUTPUT);
hal.gpio->pinMode(SPI3_MISO, GPIO_INPUT);
/* UMSELn1 and UMSELn2: USART in SPI Master mode */
UCSR3C = _BV(UMSEL31) | _BV(UMSEL30);
/* Enable RX and TX. */
UCSR3B = _BV(RXEN3) | _BV(TXEN3);
/* Setup chip select pin */
_cs_pin->mode(GPIO_OUTPUT);
_cs_pin->write(1);
}
AP_HAL::Semaphore* AVRSPI3DeviceDriver::get_semaphore() {
return &_semaphore;
}
void AVRSPI3DeviceDriver::cs_assert() {
/* set the device UCSRnC configuration bits.
* only sets data order, clock phase, and clock polarity bits (lowest
* three bits) */
const uint8_t new_ucsr3c = UCSR3C | (_ucsr3c & (0x07));
UCSR3C = new_ucsr3c;
/* set the device baud rate */
UBRR3 = _ubrr3;
_cs_pin->write(0);
}
void AVRSPI3DeviceDriver::cs_release() {
_cs_pin->write(1);
}
uint8_t AVRSPI3DeviceDriver::transfer(uint8_t data) {
/* Wait for empty transmit buffer */
while ( !( UCSR3A & _BV(UDRE3)) ) ;
/* Put data into buffer, sends the data */
UDR3 = data;
/* Wait for data to be received */
while ( !(UCSR3A & _BV(RXC3)) ) ;
/* Get and return received data from buffer */
return UDR3;
}

View File

@ -0,0 +1,89 @@
#ifndef __AP_HAL_AVR_SPI_DEVICES_H__
#define __AP_HAL_AVR_SPI_DEVICES_H__
#include <AP_HAL.h>
#include "AP_HAL_AVR_Namespace.h"
class AP_HAL_AVR::AVRSPI0DeviceDriver : public AP_HAL::SPIDeviceDriver {
public:
AVRSPI0DeviceDriver(
AP_HAL_AVR::AVRDigitalSource *cs_pin,
uint8_t spcr,
uint8_t spsr
) :
_cs_pin(cs_pin),
_spcr(spcr),
_spsr(spsr)
{}
void init();
AP_HAL::Semaphore* get_semaphore();
void cs_assert();
void cs_release();
uint8_t transfer(uint8_t data);
private:
static AP_HAL_AVR::AVRSemaphore _semaphore;
AP_HAL_AVR::AVRDigitalSource *_cs_pin;
const uint8_t _spcr;
const uint8_t _spsr;
};
class AP_HAL_AVR::AVRSPI2DeviceDriver : public AP_HAL::SPIDeviceDriver {
public:
AVRSPI2DeviceDriver(
AP_HAL_AVR::AVRDigitalSource *cs_pin,
uint8_t ucsr2c,
uint16_t ubrr2
) :
_cs_pin(cs_pin),
_ucsr2c(ucsr2c),
_ubrr2(ubrr2)
{}
void init();
AP_HAL::Semaphore* get_semaphore();
void cs_assert();
void cs_release();
uint8_t transfer(uint8_t data);
private:
static AP_HAL_AVR::AVRSemaphore _semaphore;
AP_HAL_AVR::AVRDigitalSource *_cs_pin;
uint8_t _ucsr2c;
uint16_t _ubrr2;
};
class AP_HAL_AVR::AVRSPI3DeviceDriver : public AP_HAL::SPIDeviceDriver {
public:
AVRSPI3DeviceDriver(
AP_HAL_AVR::AVRDigitalSource *cs_pin,
uint8_t ucsr3c,
uint16_t ubrr3
) :
_cs_pin(cs_pin),
_ucsr3c(ucsr3c),
_ubrr3(ubrr3)
{}
void init();
AP_HAL::Semaphore* get_semaphore();
void cs_assert();
void cs_release();
uint8_t transfer(uint8_t data);
private:
static AP_HAL_AVR::AVRSemaphore _semaphore;
AP_HAL_AVR::AVRDigitalSource *_cs_pin;
uint8_t _ucsr3c;
uint16_t _ubrr3;
};
#endif // __AP_HAL_AVR_SPI_DEVICES_H__

View File

@ -1,67 +0,0 @@
#include <avr/io.h>
#include "utility/pins_arduino_mega.h"
#include <AP_HAL.h>
#include "SPIDriver.h"
using namespace AP_HAL_AVR;
extern const AP_HAL::HAL& hal;
void ArduinoSPIDriver::init(void* machtnichts) {
hal.gpio->pinMode(SCK, GPIO_OUTPUT);
hal.gpio->pinMode(MOSI, GPIO_OUTPUT);
hal.gpio->pinMode(SS, GPIO_OUTPUT);
hal.gpio->write(SCK, 0);
hal.gpio->write(MOSI,0);
hal.gpio->write(SS, 0);
SPCR |= _BV(MSTR);
SPCR |= _BV(SPE);
set_freq( 1000000);
}
void ArduinoSPIDriver::set_freq(uint32_t freq_hz) {
const uint16_t freq_khz = (uint16_t)(freq_hz / 1000UL);
const uint16_t fcpu_khz = (uint16_t)(F_CPU / 1000UL);
const int16_t div = fcpu_khz / freq_khz;
/* can't divide clock by more than 128. */
uint8_t b = _divider_bits( div > 128 ? 128 : ((uint8_t) div));
_set_clock_divider_bits(b);
}
/* from Arduino SPI.h:
#define SPI_CLOCK_DIV2 0x04
#define SPI_CLOCK_DIV4 0x00
#define SPI_CLOCK_DIV8 0x05
#define SPI_CLOCK_DIV16 0x01
#define SPI_CLOCK_DIV32 0x06
#define SPI_CLOCK_DIV64 0x02
#define SPI_CLOCK_DIV128 0x03
*/
uint8_t ArduinoSPIDriver::_divider_bits(uint8_t div) {
/* Closest bits for divider without going over (ending up faster) */
if (div > 64) return 0x03;
if (div > 32) return 0x02;
if (div > 16) return 0x06;
if (div > 8) return 0x01;
if (div > 4) return 0x05;
if (div > 2) return 0x00;
return 0x04;
}
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
void ArduinoSPIDriver::_set_clock_divider_bits(uint8_t b) {
SPCR = (SPCR & ~SPI_CLOCK_MASK) | ( b & SPI_CLOCK_MASK);
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((b >> 2) & SPI_2XCLOCK_MASK);
}
uint8_t ArduinoSPIDriver::transfer(uint8_t data) {
SPDR = data;
while(!(SPSR & _BV(SPIF)));
return SPDR;
}

View File

@ -1,20 +1,38 @@
#ifndef __AP_HAL_ARDUINO_SPI_DRIVER_H__ #ifndef __AP_HAL_AVR_SPI_DRIVER_H__
#define __AP_HAL_ARDUINO_SPI_DRIVER_H__ #define __AP_HAL_AVR_SPI_DRIVER_H__
#include <AP_HAL.h> #include <AP_HAL.h>
#include "AP_HAL_AVR_Namespace.h" #include "AP_HAL_AVR_Namespace.h"
#include "GPIO.h"
#include "SPIDevices.h"
#include "Semaphore.h"
class AP_HAL_AVR::ArduinoSPIDriver : public AP_HAL::SPIDriver { class AP_HAL_AVR::APM1SPIDeviceManager : public AP_HAL::SPIDeviceManager {
public: public:
ArduinoSPIDriver() {}
void init(void* machtnichts); void init(void* machtnichts);
void set_freq(uint32_t freq_hz); AP_HAL::SPIDeviceDriver* device(enum AP_HAL::SPIDevice d);
uint8_t transfer(uint8_t data);
private: private:
uint8_t _divider_bits(uint8_t divider); AVRSPI0DeviceDriver* _dataflash;
void _set_clock_divider_bits(uint8_t b); AVRSPI0DeviceDriver* _optflow;
AVRSPI2DeviceDriver* _adc;
}; };
#endif // __AP_HAL_ARDUINO_SPI_DRIVER_H__ class AP_HAL_AVR::APM2SPIDeviceManager : public AP_HAL::SPIDeviceManager {
public:
void init(void* machtnichts);
AP_HAL::SPIDeviceDriver* device(enum AP_HAL::SPIDevice d);
private:
AVRSPI0DeviceDriver* _mpu6k;
AVRSPI0DeviceDriver* _ms5611;
AVRSPI0DeviceDriver* _optflow_spi0;
AVRSPI3DeviceDriver* _dataflash;
AVRSPI3DeviceDriver* _optflow_spi3;
};
#endif // __AP_HAL_AVR_SPI_DRIVER_H__

View File

@ -2,6 +2,7 @@
#include <AP_HAL.h> #include <AP_HAL.h>
#include <AP_HAL_AVR.h> #include <AP_HAL_AVR.h>
#include "Semaphore.h"
using namespace AP_HAL_AVR; using namespace AP_HAL_AVR;
extern const AP_HAL::HAL& hal; extern const AP_HAL::HAL& hal;

View File

@ -17,30 +17,33 @@
const AP_HAL_AVR::HAL_AVR& hal = AP_HAL_AVR_APM2; const AP_HAL_AVR::HAL_AVR& hal = AP_HAL_AVR_APM2;
const uint8_t _cs_pin = 53;
const uint8_t _baro_cs_pin = 40; const uint8_t _baro_cs_pin = 40;
AP_HAL::SPIDeviceDriver* spidev;
static void register_write(uint8_t reg, uint8_t val) { static void register_write(uint8_t reg, uint8_t val) {
hal.gpio->write(_cs_pin, 0); hal.console->printf_P(PSTR("write reg %d val %d\r\n"),
hal.spi->transfer(reg); (int) reg, (int) val);
hal.spi->transfer(val); spidev->cs_assert();
hal.gpio->write(_cs_pin, 1); spidev->transfer(reg);
spidev->transfer(val);
spidev->cs_release();
} }
static uint8_t register_read(uint8_t reg) { static uint8_t register_read(uint8_t reg) {
/* set most significant bit to read register */ /* set most significant bit to read register */
uint8_t regaddr = reg | 0x80; uint8_t regaddr = reg | 0x80;
hal.gpio->write(_cs_pin, 0); spidev->cs_assert();
hal.spi->transfer(regaddr); spidev->transfer(regaddr);
uint8_t val = hal.spi->transfer(0); uint8_t val = spidev->transfer(0);
hal.gpio->write(_cs_pin, 1); spidev->cs_release();
return val; return val;
} }
static uint16_t spi_read_16(void) { static uint16_t spi_read_16(void) {
uint8_t byte_h, byte_l; uint8_t byte_h, byte_l;
byte_h = hal.spi->transfer(0); byte_h = spidev->transfer(0);
byte_l = hal.spi->transfer(0); byte_l = spidev->transfer(0);
return (((int16_t) byte_h)<< 8) | byte_l; return (((int16_t) byte_h)<< 8) | byte_l;
} }
@ -95,30 +98,28 @@ static void mpu6k_init(void) {
static void mpu6k_read(int16_t* data) { static void mpu6k_read(int16_t* data) {
hal.gpio->write(_cs_pin, 0); spidev->cs_assert();
hal.spi->transfer( MPUREG_ACCEL_XOUT_H | 0x80 ); spidev->transfer( MPUREG_ACCEL_XOUT_H | 0x80 );
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
data[i] = spi_read_16(); data[i] = spi_read_16();
} }
hal.gpio->write(_cs_pin, 1); spidev->cs_release();
} }
static void setup() { static void setup() {
hal.console->printf_P(PSTR("Initializing MPU6000\r\n")); hal.console->printf_P(PSTR("Initializing MPU6000\r\n"));
spidev = hal.spi->device(AP_HAL::SPIDevice_MPU6000);
#if 0
/* Setup the barometer cs to stop it from holding the bus */ /* Setup the barometer cs to stop it from holding the bus */
hal.gpio->pinMode(_baro_cs_pin, GPIO_OUTPUT); hal.gpio->pinMode(_baro_cs_pin, GPIO_OUTPUT);
hal.gpio->write(_baro_cs_pin, 1); hal.gpio->write(_baro_cs_pin, 1);
#endif
/* Setup CS pin hardware */ spidev->cs_assert();
hal.gpio->pinMode(_cs_pin, GPIO_OUTPUT);
hal.gpio->write(_cs_pin, 1);
hal.scheduler->delay(1);
uint8_t spcr = SPCR; uint8_t spcr = SPCR;
uint8_t spsr = SPSR; uint8_t spsr = SPSR;
hal.console->printf_P(PSTR("SPCR 0x%x, SPSR 0x%x\r\n"), spidev->cs_release();
(int)spcr, (int)spsr);
mpu6k_init(); mpu6k_init();
} }
@ -132,9 +133,6 @@ static void loop() {
hal.scheduler->delay(10); hal.scheduler->delay(10);
} }
extern "C" { extern "C" {
int main (void) { int main (void) {
hal.init(NULL); hal.init(NULL);