AP_HAL_AVR Dataflash implemented, tested for APM2
* Need to get my APM1 board from home to test it on there...
This commit is contained in:
parent
9beba972c8
commit
06441b4117
@ -19,6 +19,8 @@ public:
|
||||
virtual void read_mfg_id() = 0;
|
||||
virtual bool media_present() = 0;
|
||||
virtual uint16_t num_pages() = 0;
|
||||
virtual uint8_t mfg_id() = 0;
|
||||
virtual uint16_t device_id() = 0;
|
||||
|
||||
virtual uint16_t get_page() = 0;
|
||||
virtual uint16_t get_write_page() = 0;
|
||||
|
@ -14,9 +14,11 @@ public:
|
||||
virtual void init(void *implspecific) = 0;
|
||||
virtual void read_mfg_id() = 0;
|
||||
virtual bool media_present() = 0;
|
||||
virtual uint16_t num_pages() = 0;
|
||||
|
||||
/* Concrete public methods: */
|
||||
uint16_t num_pages() { return _num_pages; }
|
||||
uint8_t mfg_id() { return _mfg; }
|
||||
uint16_t device_id() { return _device; }
|
||||
uint16_t get_page() { return _read_page_addr - 1; }
|
||||
uint16_t get_write_page() { return _page_addr; }
|
||||
|
||||
@ -48,20 +50,38 @@ protected:
|
||||
/* Implementation-specific private methods: */
|
||||
virtual void _wait_ready() = 0;
|
||||
virtual void _page_to_buffer(uint8_t buffer_num, uint16_t page_addr) = 0;
|
||||
virtual void _buffer_to_page(uint8_t buffer_num, uint16_t page_addr,
|
||||
bool wait) = 0;
|
||||
virtual void _page_erase(uint16_t page_addr) = 0;
|
||||
virtual void _block_erase(uint16_t block_addr) = 0;
|
||||
virtual void _chip_erase() = 0;
|
||||
|
||||
virtual void _buffer_write(uint8_t buffer_num, uint16_t page_addr,
|
||||
uint8_t data) = 0;
|
||||
virtual uint8_t _buffer_read(uint8_t buffer_num, uint16_t page_addr) = 0;
|
||||
|
||||
/* Concrete private methods: */
|
||||
|
||||
int16_t _find_last_page();
|
||||
int16_t _find_last_page_of_log(uint16_t log_num);
|
||||
bool _check_wrapped();
|
||||
|
||||
/* Instance variables: */
|
||||
uint8_t _buffer_num;
|
||||
uint8_t _read_buffer_num;
|
||||
uint16_t _buffer_idx;
|
||||
uint16_t _read_buffer_idx;
|
||||
uint16_t _page_addr;
|
||||
uint16_t _read_page_addr;
|
||||
uint8_t _stop_write;
|
||||
bool _stop_write;
|
||||
uint16_t _file_num;
|
||||
uint16_t _file_page;
|
||||
|
||||
/* Instance variables which should be initialized by the child class: */
|
||||
uint8_t _mfg;
|
||||
uint16_t _device;
|
||||
uint16_t _page_size;
|
||||
uint16_t _num_pages;
|
||||
};
|
||||
|
||||
/* APM1Dataflash and APM2Dataflash: fully concrete classes implementing
|
||||
@ -72,10 +92,24 @@ public:
|
||||
void init(void* machtnichts);
|
||||
void read_mfg_id();
|
||||
bool media_present();
|
||||
uint16_t num_pages();
|
||||
private:
|
||||
void _wait_ready();
|
||||
|
||||
void _page_to_buffer(uint8_t buffer_num, uint16_t page_addr);
|
||||
void _buffer_to_page(uint8_t buffer_num, uint16_t page_addr, bool wait);
|
||||
|
||||
void _page_erase(uint16_t page_addr);
|
||||
void _block_erase(uint16_t block_addr);
|
||||
void _chip_erase();
|
||||
|
||||
void _buffer_write(uint8_t buffer_num, uint16_t page_addr, uint8_t data);
|
||||
uint8_t _buffer_read(uint8_t buffer_num, uint16_t page_addr);
|
||||
|
||||
uint8_t _read_status_reg();
|
||||
uint8_t _read_status();
|
||||
|
||||
void _cs_active();
|
||||
void _cs_inactive();
|
||||
};
|
||||
|
||||
class AP_HAL_AVR::APM2Dataflash : public AP_HAL_AVR::CommonDataflash {
|
||||
@ -83,10 +117,25 @@ public:
|
||||
void init(void* machtnichts);
|
||||
void read_mfg_id();
|
||||
bool media_present();
|
||||
uint16_t num_pages();
|
||||
private:
|
||||
void _wait_ready();
|
||||
|
||||
void _page_to_buffer(uint8_t buffer_num, uint16_t page_addr);
|
||||
void _buffer_to_page(uint8_t buffer_num, uint16_t page_addr, bool wait);
|
||||
|
||||
void _page_erase(uint16_t page_addr);
|
||||
void _block_erase(uint16_t block_addr);
|
||||
void _chip_erase();
|
||||
|
||||
void _buffer_write(uint8_t buffer_num, uint16_t page_addr, uint8_t data);
|
||||
uint8_t _buffer_read(uint8_t buffer_num, uint16_t page_addr);
|
||||
|
||||
uint8_t _read_status_reg();
|
||||
uint8_t _read_status();
|
||||
|
||||
void _cs_active();
|
||||
void _cs_inactive();
|
||||
uint8_t _transfer(uint8_t data);
|
||||
};
|
||||
|
||||
#endif // __AP_HAL_AVR_DATAFLASH_H__
|
||||
|
@ -1,30 +1,230 @@
|
||||
|
||||
#include <AP_HAL.h>
|
||||
#include "Dataflash.h"
|
||||
using namespace AP_HAL_AVR;
|
||||
|
||||
extern const AP_HAL::HAL& hal;
|
||||
|
||||
/* flash size */
|
||||
#define DF_LAST_PAGE 4096
|
||||
|
||||
/* Arduino Mega SPI pins */
|
||||
#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) */
|
||||
#define DF_TRANSFER_PAGE_TO_BUFFER_1 0x53
|
||||
#define DF_TRANSFER_PAGE_TO_BUFFER_2 0x55
|
||||
#define DF_STATUS_REGISTER_READ 0xD7
|
||||
#define DF_READ_MANUFACTURER_AND_DEVICE_ID 0x9F
|
||||
#define DF_PAGE_READ 0xD2
|
||||
#define DF_BUFFER_1_READ 0xD4
|
||||
#define DF_BUFFER_2_READ 0xD6
|
||||
#define DF_BUFFER_1_WRITE 0x84
|
||||
#define DF_BUFFER_2_WRITE 0x87
|
||||
#define DF_BUFFER_1_TO_PAGE_WITH_ERASE 0x83
|
||||
#define DF_BUFFER_2_TO_PAGE_WITH_ERASE 0x86
|
||||
#define DF_PAGE_ERASE 0x81
|
||||
#define DF_BLOCK_ERASE 0x50
|
||||
#define DF_SECTOR_ERASE 0x7C
|
||||
#define DF_CHIP_ERASE_0 0xC7
|
||||
#define DF_CHIP_ERASE_1 0x94
|
||||
#define DF_CHIP_ERASE_2 0x80
|
||||
#define DF_CHIP_ERASE_3 0x9A
|
||||
|
||||
|
||||
void APM1Dataflash::init(void* machtnichts) {
|
||||
hal.gpio->pinMode(DF_DATAOUT, 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 */
|
||||
hal.gpio->write(DF_RESET, 0);
|
||||
hal.scheduler->delay(1);
|
||||
hal.gpio->write(DF_RESET, 1);
|
||||
|
||||
_cs_inactive();
|
||||
|
||||
hal.spi->set_freq(8000000L);
|
||||
|
||||
_num_pages = DF_LAST_PAGE - 1;
|
||||
uint8_t status = _read_status_reg();
|
||||
_page_size = (status & 0x01) ? 512 : 528;
|
||||
}
|
||||
|
||||
void APM1Dataflash::read_mfg_id() {
|
||||
|
||||
_cs_active();
|
||||
hal.spi->transfer(DF_READ_MANUFACTURER_AND_DEVICE_ID);
|
||||
_mfg = hal.spi->transfer(0xFF);
|
||||
_device = hal.spi->transfer(0xFF);
|
||||
_device = (_device << 8) | hal.spi->transfer(0xFF);
|
||||
/* fourth byte is dont care */
|
||||
hal.spi->transfer(0xFF);
|
||||
_cs_inactive();
|
||||
}
|
||||
|
||||
bool APM1Dataflash::media_present() {
|
||||
|
||||
}
|
||||
|
||||
uint16_t APM1Dataflash::num_pages() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void APM1Dataflash::_wait_ready() {
|
||||
|
||||
while(!_read_status());
|
||||
}
|
||||
|
||||
void APM1Dataflash::_page_to_buffer(uint8_t buffer_num, uint16_t page_addr) {
|
||||
_cs_active();
|
||||
if (_buffer_num == 1) {
|
||||
hal.spi->transfer(DF_TRANSFER_PAGE_TO_BUFFER_1);
|
||||
} else {
|
||||
hal.spi->transfer(DF_TRANSFER_PAGE_TO_BUFFER_2);
|
||||
}
|
||||
|
||||
if (_page_size == 512) {
|
||||
hal.spi->transfer( page_addr >> 7 );
|
||||
hal.spi->transfer( page_addr << 1 );
|
||||
} else {
|
||||
hal.spi->transfer( page_addr >> 6 );
|
||||
hal.spi->transfer( page_addr << 2 );
|
||||
}
|
||||
/* finally send one dont care byte */
|
||||
hal.spi->transfer(0x00);
|
||||
|
||||
_cs_inactive();
|
||||
_wait_ready();
|
||||
}
|
||||
|
||||
void APM1Dataflash::_buffer_to_page(uint8_t buffer_num, uint16_t page_addr, bool wait) {
|
||||
_cs_active();
|
||||
if (_buffer_num == 1) {
|
||||
hal.spi->transfer(DF_BUFFER_1_TO_PAGE_WITH_ERASE);
|
||||
} else {
|
||||
hal.spi->transfer(DF_BUFFER_2_TO_PAGE_WITH_ERASE);
|
||||
}
|
||||
|
||||
if (_page_size == 512) {
|
||||
hal.spi->transfer( page_addr >> 7 );
|
||||
hal.spi->transfer( page_addr << 1 );
|
||||
} else {
|
||||
hal.spi->transfer( page_addr >> 6 );
|
||||
hal.spi->transfer( page_addr << 2 );
|
||||
}
|
||||
/* finally send one dont care byte */
|
||||
hal.spi->transfer(0x00);
|
||||
|
||||
_cs_inactive();
|
||||
if (wait) {
|
||||
_wait_ready();
|
||||
}
|
||||
}
|
||||
|
||||
void APM1Dataflash::_page_erase(uint16_t page_addr) {
|
||||
_cs_active();
|
||||
hal.spi->transfer(DF_PAGE_ERASE);
|
||||
|
||||
if (_page_size == 512) {
|
||||
hal.spi->transfer( page_addr >> 7 );
|
||||
hal.spi->transfer( page_addr << 1 );
|
||||
} else {
|
||||
hal.spi->transfer( page_addr >> 6 );
|
||||
hal.spi->transfer( page_addr << 2 );
|
||||
}
|
||||
|
||||
/* finally send one dont care byte */
|
||||
hal.spi->transfer(0x00);
|
||||
_cs_inactive();
|
||||
_wait_ready();
|
||||
}
|
||||
|
||||
void APM1Dataflash::_block_erase(uint16_t block_addr) {
|
||||
_cs_active();
|
||||
hal.spi->transfer(DF_BLOCK_ERASE);
|
||||
|
||||
if (_page_size == 512) {
|
||||
hal.spi->transfer( block_addr >> 7 );
|
||||
hal.spi->transfer( block_addr << 1 );
|
||||
} else {
|
||||
hal.spi->transfer( block_addr >> 6 );
|
||||
hal.spi->transfer( block_addr << 2 );
|
||||
}
|
||||
/* finally send one dont care byte */
|
||||
hal.spi->transfer(0x00);
|
||||
_cs_inactive();
|
||||
_wait_ready();
|
||||
}
|
||||
|
||||
void APM1Dataflash::_chip_erase() {
|
||||
_cs_active();
|
||||
hal.spi->transfer(DF_CHIP_ERASE_0);
|
||||
hal.spi->transfer(DF_CHIP_ERASE_1);
|
||||
hal.spi->transfer(DF_CHIP_ERASE_2);
|
||||
hal.spi->transfer(DF_CHIP_ERASE_3);
|
||||
_cs_inactive();
|
||||
|
||||
while(!_read_status()) {
|
||||
hal.scheduler->delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
void APM1Dataflash::_buffer_write(uint8_t buffer_num, uint16_t page_addr, uint8_t data) {
|
||||
_cs_active();
|
||||
if (buffer_num == 1) {
|
||||
hal.spi->transfer(DF_BUFFER_1_WRITE);
|
||||
} else {
|
||||
hal.spi->transfer(DF_BUFFER_2_WRITE);
|
||||
}
|
||||
/* Don't care */
|
||||
hal.spi->transfer(0);
|
||||
/* Internal buffer address */
|
||||
hal.spi->transfer((uint8_t)(page_addr >> 8));
|
||||
hal.spi->transfer((uint8_t)(page_addr & 0xFF));
|
||||
/* Byte to write */
|
||||
hal.spi->transfer(data);
|
||||
_cs_inactive();
|
||||
}
|
||||
|
||||
uint8_t APM1Dataflash::_buffer_read(uint8_t buffer_num, uint16_t page_addr) {
|
||||
_cs_active();
|
||||
if (buffer_num == 1) {
|
||||
hal.spi->transfer(DF_BUFFER_1_READ);
|
||||
} else {
|
||||
hal.spi->transfer(DF_BUFFER_2_READ);
|
||||
}
|
||||
/* Don't care */
|
||||
hal.spi->transfer(0);
|
||||
/* Internal buffer address */
|
||||
hal.spi->transfer((uint8_t)(page_addr >> 8));
|
||||
hal.spi->transfer((uint8_t)(page_addr & 0xFF));
|
||||
/* Don't care */
|
||||
hal.spi->transfer(0);
|
||||
/* Read data byte */
|
||||
uint8_t res = hal.spi->transfer(0);
|
||||
_cs_inactive();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline uint8_t APM1Dataflash::_read_status_reg() {
|
||||
_cs_active();
|
||||
hal.spi->transfer(DF_STATUS_REGISTER_READ);
|
||||
/* Read the first byte of the result */
|
||||
uint8_t res = hal.spi->transfer(0);
|
||||
_cs_inactive();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline uint8_t APM1Dataflash::_read_status() {
|
||||
/* Busy status is the top bit of the status register */
|
||||
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);
|
||||
}
|
||||
|
@ -1,30 +1,280 @@
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <AP_HAL.h>
|
||||
#include "Dataflash.h"
|
||||
using namespace AP_HAL_AVR;
|
||||
|
||||
extern const AP_HAL::HAL& hal;
|
||||
|
||||
/* Connected to USART3 in SPI mode */
|
||||
#define DF_DATAOUT 14 /* MOSI */
|
||||
#define DF_DATAIN 15 /* MISO */
|
||||
#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)
|
||||
#define DF_TRANSFER_PAGE_TO_BUFFER_1 0x53
|
||||
#define DF_TRANSFER_PAGE_TO_BUFFER_2 0x55
|
||||
#define DF_STATUS_REGISTER_READ 0xD7
|
||||
#define DF_READ_MANUFACTURER_AND_DEVICE_ID 0x9F
|
||||
#define DF_PAGE_READ 0xD2
|
||||
#define DF_BUFFER_1_READ 0xD4
|
||||
#define DF_BUFFER_2_READ 0xD6
|
||||
#define DF_BUFFER_1_WRITE 0x84
|
||||
#define DF_BUFFER_2_WRITE 0x87
|
||||
#define DF_BUFFER_1_TO_PAGE_WITH_ERASE 0x83
|
||||
#define DF_BUFFER_2_TO_PAGE_WITH_ERASE 0x86
|
||||
#define DF_PAGE_ERASE 0x81
|
||||
#define DF_BLOCK_ERASE 0x50
|
||||
#define DF_SECTOR_ERASE 0x7C
|
||||
#define DF_CHIP_ERASE_0 0xC7
|
||||
#define DF_CHIP_ERASE_1 0x94
|
||||
#define DF_CHIP_ERASE_2 0x80
|
||||
#define DF_CHIP_ERASE_3 0x9A
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOGD(format, ...) do { hal.uart0->printf_P(PSTR("DBG/Dataflash: "format), __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define LOGD(format, ...) do {} while(0)
|
||||
#endif
|
||||
|
||||
|
||||
void APM2Dataflash::init(void* machtnichts) {
|
||||
/* setup gpio pins */
|
||||
hal.gpio->pinMode(DF_DATAOUT, GPIO_OUTPUT);
|
||||
hal.gpio->pinMode(DF_DATAIN, GPIO_OUTPUT);
|
||||
hal.gpio->pinMode(DF_SLAVESELECT, GPIO_OUTPUT);
|
||||
hal.gpio->pinMode(DF_RESET, GPIO_OUTPUT);
|
||||
hal.gpio->pinMode(DF_CARDDETECT, GPIO_INPUT);
|
||||
|
||||
/* Reset device */
|
||||
hal.gpio->write(DF_RESET, 0);
|
||||
hal.scheduler->delay(1);
|
||||
hal.gpio->write(DF_RESET, 1);
|
||||
|
||||
_cs_inactive();
|
||||
|
||||
/* 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();
|
||||
_page_size = (status & 0x01) ? 512 : 528;
|
||||
LOGD("_page_size set to %d\r\n", _page_size);
|
||||
|
||||
read_mfg_id();
|
||||
/* from page 22 of the spec, density code decoder: */
|
||||
uint8_t density_code = (_device >> 8) & 0x1F;
|
||||
if (density_code == 0x7) {
|
||||
/* 32 Mbit */
|
||||
_num_pages = 8191;
|
||||
} else if (density_code == 0x06) {
|
||||
/* 16 Mbit */
|
||||
_num_pages = 4095;
|
||||
} else {
|
||||
/* Unknown */
|
||||
_num_pages = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void APM2Dataflash::read_mfg_id() {
|
||||
|
||||
_cs_active();
|
||||
_transfer(DF_READ_MANUFACTURER_AND_DEVICE_ID);
|
||||
_mfg = _transfer(0xFF);
|
||||
_device = _transfer(0xFF);
|
||||
_device = (_device << 8) | _transfer(0xFF);
|
||||
_transfer(0xFF);
|
||||
_cs_inactive();
|
||||
}
|
||||
|
||||
bool APM2Dataflash::media_present() {
|
||||
|
||||
}
|
||||
|
||||
uint16_t APM2Dataflash::num_pages() {
|
||||
|
||||
/* Assume the card is present if we read a valid mfg id. */
|
||||
return _num_pages >= 4095;
|
||||
}
|
||||
|
||||
void APM2Dataflash::_wait_ready() {
|
||||
|
||||
while(!_read_status());
|
||||
}
|
||||
|
||||
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);
|
||||
_cs_active();
|
||||
if (_buffer_num == 1) {
|
||||
_transfer(DF_TRANSFER_PAGE_TO_BUFFER_1);
|
||||
} else {
|
||||
_transfer(DF_TRANSFER_PAGE_TO_BUFFER_2);
|
||||
}
|
||||
|
||||
if (_page_size == 512) {
|
||||
_transfer((uint8_t)(page_addr >> 7));
|
||||
_transfer((uint8_t)(page_addr << 1));
|
||||
} else {
|
||||
_transfer((uint8_t)(page_addr >> 6));
|
||||
_transfer((uint8_t)(page_addr << 2));
|
||||
}
|
||||
/* finally send one dont care byte */
|
||||
_transfer(0x00);
|
||||
|
||||
_cs_inactive();
|
||||
_wait_ready();
|
||||
}
|
||||
|
||||
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",
|
||||
(int) buffer_num, page_addr);
|
||||
_cs_active();
|
||||
if (_buffer_num == 1) {
|
||||
_transfer(DF_BUFFER_1_TO_PAGE_WITH_ERASE);
|
||||
} else {
|
||||
_transfer(DF_BUFFER_2_TO_PAGE_WITH_ERASE);
|
||||
}
|
||||
|
||||
if (_page_size == 512) {
|
||||
_transfer((uint8_t)(page_addr >> 7));
|
||||
_transfer((uint8_t)(page_addr << 1));
|
||||
} else {
|
||||
_transfer((uint8_t)(page_addr >> 6));
|
||||
_transfer((uint8_t)(page_addr << 2));
|
||||
}
|
||||
/* finally send one dont care byte */
|
||||
_transfer(0x00);
|
||||
|
||||
_cs_inactive();
|
||||
if (wait) {
|
||||
_wait_ready();
|
||||
}
|
||||
}
|
||||
|
||||
void APM2Dataflash::_page_erase(uint16_t page_addr) {
|
||||
_cs_active();
|
||||
_transfer(DF_PAGE_ERASE);
|
||||
|
||||
if (_page_size == 512) {
|
||||
_transfer( page_addr >> 7 );
|
||||
_transfer( page_addr << 1 );
|
||||
} else {
|
||||
_transfer( page_addr >> 6 );
|
||||
_transfer( page_addr << 2 );
|
||||
}
|
||||
|
||||
/* finally send one dont care byte */
|
||||
_transfer(0x00);
|
||||
_cs_inactive();
|
||||
_wait_ready();
|
||||
}
|
||||
|
||||
void APM2Dataflash::_block_erase(uint16_t block_addr) {
|
||||
LOGD("_block_erase %d\r\n", block_addr);
|
||||
_cs_active();
|
||||
_transfer(DF_BLOCK_ERASE);
|
||||
|
||||
if (_page_size == 512) {
|
||||
_transfer( block_addr >> 7 );
|
||||
_transfer( block_addr << 1 );
|
||||
} else {
|
||||
_transfer( block_addr >> 6 );
|
||||
_transfer( block_addr << 2 );
|
||||
}
|
||||
/* finally send one dont care byte */
|
||||
_transfer(0x00);
|
||||
_cs_inactive();
|
||||
_wait_ready();
|
||||
}
|
||||
|
||||
void APM2Dataflash::_chip_erase() {
|
||||
_cs_active();
|
||||
_transfer(DF_CHIP_ERASE_0);
|
||||
_transfer(DF_CHIP_ERASE_1);
|
||||
_transfer(DF_CHIP_ERASE_2);
|
||||
_transfer(DF_CHIP_ERASE_3);
|
||||
_cs_inactive();
|
||||
|
||||
while(!_read_status()) {
|
||||
hal.scheduler->delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
(int) buffer_num, page_addr, (int) data);
|
||||
_cs_active();
|
||||
if (buffer_num == 1) {
|
||||
_transfer(DF_BUFFER_1_WRITE);
|
||||
} else {
|
||||
_transfer(DF_BUFFER_2_WRITE);
|
||||
}
|
||||
/* Don't care */
|
||||
_transfer(0);
|
||||
/* Internal buffer address */
|
||||
_transfer((uint8_t)(page_addr >> 8));
|
||||
_transfer((uint8_t)(page_addr & 0xFF));
|
||||
/* Byte to write */
|
||||
_transfer(data);
|
||||
_cs_inactive();
|
||||
}
|
||||
|
||||
uint8_t APM2Dataflash::_buffer_read(uint8_t buffer_num, uint16_t page_addr) {
|
||||
_cs_active();
|
||||
if (buffer_num == 1) {
|
||||
_transfer(DF_BUFFER_1_READ);
|
||||
} else {
|
||||
_transfer(DF_BUFFER_2_READ);
|
||||
}
|
||||
/* Don't care */
|
||||
_transfer(0);
|
||||
/* Internal buffer address */
|
||||
_transfer((uint8_t)(page_addr >> 8));
|
||||
_transfer((uint8_t)(page_addr & 0xFF));
|
||||
/* Don't care */
|
||||
_transfer(0);
|
||||
/* Read data byte */
|
||||
uint8_t res = _transfer(0);
|
||||
_cs_inactive();
|
||||
LOGD("_buffer_read num: %d pageaddr: %d result: %d\r\n",
|
||||
(int) buffer_num, (int) page_addr, (int) res);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline uint8_t APM2Dataflash::_read_status_reg() {
|
||||
_cs_active();
|
||||
_transfer(DF_STATUS_REGISTER_READ);
|
||||
/* Read the first byte of the result */
|
||||
uint8_t res = _transfer(0);
|
||||
_cs_inactive();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline uint8_t APM2Dataflash::_read_status() {
|
||||
/* Busy status is the top bit of the status register */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1,70 +1,364 @@
|
||||
|
||||
#include <AP_HAL.h>
|
||||
#include "Dataflash.h"
|
||||
|
||||
using namespace AP_HAL_AVR;
|
||||
|
||||
void CommonDataflash::erase_all() {
|
||||
extern const AP_HAL::HAL& hal;
|
||||
|
||||
// 0: When reach the end page stop, 1: Start overwriting from page 1
|
||||
#define DF_OVERWRITE_DATA true
|
||||
|
||||
// the last page holds the log format in first 4 bytes. Please change
|
||||
// this if (and only if!) the low level format changes
|
||||
#define DF_LOGGING_FORMAT 0x28122011
|
||||
|
||||
// we use an invalie logging format to test the chip erase
|
||||
#define DF_LOGGING_FORMAT_INVALID 0x28122012
|
||||
|
||||
void CommonDataflash::erase_all() {
|
||||
for (uint16_t i = 1; i <= (_num_pages+1)/8; i++) {
|
||||
_block_erase(i);
|
||||
hal.scheduler->delay(1);
|
||||
}
|
||||
start_write(_num_pages+1);
|
||||
write_dword(DF_LOGGING_FORMAT);
|
||||
finish_write();
|
||||
}
|
||||
|
||||
bool CommonDataflash::need_erase() {
|
||||
|
||||
start_read(_num_pages+1);
|
||||
return (read_dword() != DF_LOGGING_FORMAT);
|
||||
}
|
||||
|
||||
void CommonDataflash::start_write(int16_t page) {
|
||||
_buffer_num = 1;
|
||||
_buffer_idx = 4;
|
||||
_page_addr = page;
|
||||
_stop_write = false;
|
||||
|
||||
_wait_ready();
|
||||
|
||||
_buffer_write(_buffer_num, 0, _file_num >> 8 );
|
||||
_buffer_write(_buffer_num, 1, _file_num&0xFF );
|
||||
_buffer_write(_buffer_num, 2, _file_page >> 8 );
|
||||
_buffer_write(_buffer_num, 3, _file_page&0xFF );
|
||||
}
|
||||
|
||||
void CommonDataflash::finish_write() {
|
||||
_buffer_idx = 0;
|
||||
/* Write buffer to memory, no wait. */
|
||||
_buffer_to_page(_buffer_num, _page_addr, false);
|
||||
|
||||
_page_addr++;
|
||||
if (DF_OVERWRITE_DATA) {
|
||||
if (_page_addr > _num_pages) {
|
||||
_page_addr = 1;
|
||||
}
|
||||
} else {
|
||||
if (_page_addr > _num_pages) {
|
||||
_stop_write = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* switch buffer to continue writing */
|
||||
_buffer_num = (_buffer_num == 1) ? 2 : 1;
|
||||
}
|
||||
|
||||
void CommonDataflash::write_byte(uint8_t data) {
|
||||
if (_stop_write) return;
|
||||
_buffer_write( _buffer_num, _buffer_idx, data );
|
||||
_buffer_idx++;
|
||||
/* end of buffer? */
|
||||
if ( _buffer_idx > _page_size) {
|
||||
/* 4 bytes for filenumber, filepage */
|
||||
_buffer_idx = 4;
|
||||
/* write buffer to memory, no waiting */
|
||||
_buffer_to_page(_buffer_num, _page_addr, false);
|
||||
_page_addr++;
|
||||
if (DF_OVERWRITE_DATA) {
|
||||
if (_page_addr > _num_pages) {
|
||||
_page_addr = 1;
|
||||
}
|
||||
} else {
|
||||
if (_page_addr > _num_pages) {
|
||||
_stop_write = true;
|
||||
}
|
||||
}
|
||||
/* switch buffer to continue writing */
|
||||
_buffer_num = (_buffer_num == 1) ? 2 : 1;
|
||||
|
||||
/* We are starting a new page. write filenumber and filepage. */
|
||||
_buffer_write(_buffer_num, 0, _file_num >> 8 );
|
||||
_buffer_write(_buffer_num, 1, _file_num&0xFF );
|
||||
_buffer_write(_buffer_num, 2, _file_page >> 8 );
|
||||
_buffer_write(_buffer_num, 3, _file_page&0xFF );
|
||||
}
|
||||
}
|
||||
|
||||
void CommonDataflash::write_word(uint16_t data) {
|
||||
|
||||
write_byte( data >> 8 ); /* high byte */
|
||||
write_byte( data & 0xFF ); /* low byte */
|
||||
}
|
||||
|
||||
void CommonDataflash::write_dword(uint32_t data) {
|
||||
|
||||
write_byte( data >> 24 ); /* high byte */
|
||||
write_byte( data >> 16 );
|
||||
write_byte( data >> 8 );
|
||||
write_byte( data & 0xFF ); /* low byte */
|
||||
}
|
||||
|
||||
void CommonDataflash::start_read(int16_t page) {
|
||||
_read_buffer_num = 1;
|
||||
_read_buffer_idx = 4;
|
||||
_read_page_addr = page;
|
||||
_wait_ready();
|
||||
/* Write memory page to buffer. */
|
||||
_page_to_buffer(_read_buffer_num, _read_page_addr);
|
||||
_read_page_addr++;
|
||||
|
||||
/* We are starting a new page. Read file number and file page */
|
||||
_file_num = _buffer_read(_read_buffer_num, 0);
|
||||
_file_num = (_file_num << 8) | _buffer_read(_read_buffer_num, 1);
|
||||
_file_page = _buffer_read(_read_buffer_num, 2);
|
||||
_file_page = (_file_page << 8 ) | _buffer_read(_read_buffer_num, 3);
|
||||
}
|
||||
|
||||
uint8_t CommonDataflash::read_byte() {
|
||||
_wait_ready();
|
||||
uint8_t result = _buffer_read( _read_buffer_num, _read_buffer_idx);
|
||||
_read_buffer_idx++;
|
||||
/* Check if we reached the end of buffer */
|
||||
if ( _read_buffer_idx >= _page_size ) {
|
||||
/* 4 bytes for file number, file page */
|
||||
_read_buffer_idx = 4;
|
||||
/* Write memory page to buffer */
|
||||
_page_to_buffer(_read_buffer_num, _read_page_addr);
|
||||
_read_page_addr++;
|
||||
/* If we reach the end o fmemory, start from the beginning */
|
||||
if (_read_page_addr > _num_pages) {
|
||||
_read_page_addr = 0;
|
||||
}
|
||||
/* We are starting a new page. read file number and file page. */
|
||||
_file_num = _buffer_read(_read_buffer_num, 0);
|
||||
_file_num = (_file_num << 8) | _buffer_read(_read_buffer_num, 1);
|
||||
_file_page = _buffer_read(_read_buffer_num, 2);
|
||||
_file_page = (_file_page << 8) | _buffer_read(_read_buffer_num, 3);
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t CommonDataflash::read_word() {
|
||||
|
||||
uint16_t result = read_byte(); /* High byte */
|
||||
result = (result << 8) | read_byte(); /* Low byte */
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t CommonDataflash::read_dword() {
|
||||
|
||||
uint32_t result = read_byte(); /* High byte */
|
||||
result = (result << 8) | read_byte();
|
||||
result = (result << 8) | read_byte();
|
||||
result = (result << 8) | read_byte(); /* Low byte */
|
||||
return result;
|
||||
}
|
||||
|
||||
void CommonDataflash::set_file(uint16_t filenum) {
|
||||
|
||||
_file_num = filenum;
|
||||
_file_page = 1;
|
||||
}
|
||||
|
||||
int16_t CommonDataflash::find_last_log() {
|
||||
|
||||
int16_t last_page = _find_last_page();
|
||||
/* start_read will populate _file_num. */
|
||||
start_read(last_page);
|
||||
return _file_num;
|
||||
}
|
||||
|
||||
void CommonDataflash::get_log_boundaries(uint8_t log,
|
||||
int16_t &startpage, int16_t &endpage) {
|
||||
|
||||
/* XXX Here be dragons. I transliterated this code from DataFlash_Class::
|
||||
* get_log_boundaries - pch 04sept12 */
|
||||
int16_t num_logs = get_num_logs();
|
||||
if ( num_logs == 1 ) {
|
||||
/* Read the file number from the last page. */
|
||||
start_read(_num_pages);
|
||||
/* invariant: find_last_page_of_log does not change _file_num */
|
||||
endpage = _find_last_page_of_log((uint16_t)log);
|
||||
if (_file_num == 0xFFFF) {
|
||||
startpage = 1;
|
||||
} else {
|
||||
startpage = endpage + 1;
|
||||
}
|
||||
} else {
|
||||
if (log == 1) {
|
||||
start_read(_num_pages);
|
||||
if (_file_num == 0xFFFF) {
|
||||
startpage = 1;
|
||||
} else {
|
||||
startpage = _find_last_page() + 1;
|
||||
}
|
||||
} else {
|
||||
if ( log == (find_last_log() - num_logs + 1) ) {
|
||||
startpage = _find_last_page() + 1;
|
||||
} else {
|
||||
int16_t look = num_logs - 1;
|
||||
do { startpage = _find_last_page_of_log(look) + 1;
|
||||
look--;
|
||||
} while (startpage <= 0 && look >= 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (startpage == ( (int16_t) _num_pages + 1 ) || startpage == 0 ) {
|
||||
startpage = 1;
|
||||
}
|
||||
endpage = _find_last_page_of_log((uint16_t) log);
|
||||
if (endpage <= 0) {
|
||||
endpage = startpage;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CommonDataflash::get_num_logs() {
|
||||
/* First try _find_last_page */
|
||||
int16_t last_page = _find_last_page();
|
||||
if (last_page == 1) {
|
||||
return 0;
|
||||
}
|
||||
/* Read _file_num from page 1 */
|
||||
start_read(1);
|
||||
if (_file_num == 0xFFFF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read _file_num from last page */
|
||||
start_read(last_page);
|
||||
uint16_t last = get_file();
|
||||
/* XXX bounds check on last_page+2? */
|
||||
/* Read _file_num from last_page+2 */
|
||||
start_read(last_page+2);
|
||||
uint16_t first = _file_num;
|
||||
if (first > last) {
|
||||
/* We wrapped aroung, so get the file_num from page 1. */
|
||||
start_read(1);
|
||||
first = _file_num;
|
||||
}
|
||||
|
||||
if (last == first) {
|
||||
return 1;
|
||||
} else {
|
||||
return (last - first + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void CommonDataflash::start_new_log() {
|
||||
|
||||
uint16_t last_page = _find_last_page();
|
||||
start_read(last_page);
|
||||
/* XXX I'm pretty sure there's a bug here - find_last_log will overwrite
|
||||
* the _file_num invariant from start_read(last_page).
|
||||
* However, I'm reproducing the existing DataFlash_Class faithfully. */
|
||||
if (find_last_log() == 0 || _file_num == 0xFFFF) {
|
||||
set_file(1);
|
||||
start_write(1);
|
||||
return;
|
||||
}
|
||||
/* Check for log of length 1 page and suppress */
|
||||
if (get_file() <= 1) {
|
||||
/* Last log is too short, reuse its number */
|
||||
set_file(_file_num);
|
||||
/* and overwrite it */
|
||||
start_write(last_page);
|
||||
} else {
|
||||
/* XXX shouldn't we have checked (== 0xFFFF) before using last_page
|
||||
* in the case above? */
|
||||
if (last_page == 0xFFFF) {
|
||||
last_page = 0;
|
||||
}
|
||||
set_file(get_file() + 1);
|
||||
start_write(last_page + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t CommonDataflash::_find_last_page() {
|
||||
uint16_t top = _num_pages;
|
||||
uint16_t bottom = 1;
|
||||
start_read(bottom);
|
||||
uint32_t bottom_hash = ((uint32_t) _file_num) << 16 | _file_page;
|
||||
|
||||
while ( top - bottom > 1 ) {
|
||||
uint16_t look = (top + bottom) / 2;
|
||||
start_read(look);
|
||||
uint32_t look_hash = ((uint32_t) _file_num) << 16 | _file_page;
|
||||
if (look_hash >= 0xFFFF0000) {
|
||||
look_hash = 0;
|
||||
}
|
||||
if (look_hash < bottom_hash) {
|
||||
/* move down */
|
||||
top = look;
|
||||
} else {
|
||||
/* move up */
|
||||
bottom = look;
|
||||
bottom_hash = look_hash;
|
||||
}
|
||||
}
|
||||
|
||||
start_read(top);
|
||||
uint32_t top_hash = ((uint32_t) _file_num) << 16 | _file_page;
|
||||
if (top_hash >= 0xFFFF0000) {
|
||||
top_hash = 0;
|
||||
}
|
||||
if (top_hash > bottom_hash) {
|
||||
return top;
|
||||
} else {
|
||||
return bottom;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t CommonDataflash::_find_last_page_of_log(uint16_t log_num) {
|
||||
|
||||
uint16_t bottom, top;
|
||||
|
||||
if (_check_wrapped()) {
|
||||
start_read(1);
|
||||
bottom = _file_num;
|
||||
if (bottom > log_num) {
|
||||
bottom = _find_last_page();
|
||||
top = _num_pages;
|
||||
} else {
|
||||
bottom = 1;
|
||||
top = _find_last_page();
|
||||
}
|
||||
} else {
|
||||
bottom = 1;
|
||||
top = _find_last_page();
|
||||
}
|
||||
|
||||
uint32_t check_hash = ((int32_t) log_num) << 16 | 0xFFFF;
|
||||
while (top - bottom > 1) {
|
||||
uint16_t look = (top + bottom) / 2;
|
||||
start_read(look);
|
||||
uint32_t look_hash = ((uint32_t) _file_num) << 16 | _file_page;
|
||||
if (look_hash >= 0xFFFF0000) {
|
||||
look_hash = 0;
|
||||
}
|
||||
if (look_hash > check_hash) {
|
||||
top = look; /* move down */
|
||||
} else {
|
||||
bottom = look; /* move up */
|
||||
}
|
||||
}
|
||||
|
||||
start_read(top);
|
||||
if (_file_num == log_num) {
|
||||
return top;
|
||||
}
|
||||
start_read(bottom);
|
||||
if (_file_num == log_num) {
|
||||
return bottom;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CommonDataflash::_check_wrapped() {
|
||||
start_read(_num_pages);
|
||||
return (_file_num != 0xFFFF);
|
||||
}
|
||||
|
191
libraries/AP_HAL_AVR/examples/DataflashTest/DataflashTest.pde
Normal file
191
libraries/AP_HAL_AVR/examples/DataflashTest/DataflashTest.pde
Normal file
@ -0,0 +1,191 @@
|
||||
|
||||
#include <AP_Common.h>
|
||||
#include <AP_HAL.h>
|
||||
#include <AP_HAL_AVR.h>
|
||||
|
||||
const AP_HAL::HAL& hal = AP_HAL_AVR_APM2;
|
||||
|
||||
bool dbg = true;
|
||||
|
||||
void erase() {
|
||||
hal.uart0->println("Erasing dataflash");
|
||||
hal.dataflash->erase_all();
|
||||
}
|
||||
|
||||
void readback_page(int i);
|
||||
void single_page_readwrite() {
|
||||
|
||||
hal.uart0->println("Writing simple sequence to page 1");
|
||||
hal.dataflash->start_write(1);
|
||||
hal.dataflash->write_byte(1);
|
||||
hal.dataflash->write_byte(2);
|
||||
hal.dataflash->write_byte(3);
|
||||
hal.dataflash->write_byte(4);
|
||||
hal.dataflash->write_byte(5);
|
||||
/* Fill up the rest of the page with garbage */
|
||||
for (int i = 0; i < 600; i++) {
|
||||
hal.dataflash->write_byte(0x77);
|
||||
}
|
||||
hal.dataflash->finish_write();
|
||||
hal.scheduler->delay(100);
|
||||
readback_page(1);
|
||||
}
|
||||
|
||||
void readback_page(int i) {
|
||||
hal.uart0->printf_P(PSTR("Reading back sequence from page %d\r\n"), i);
|
||||
hal.dataflash->start_read(i);
|
||||
uint8_t v1 = hal.dataflash->read_byte();
|
||||
uint8_t v2 = hal.dataflash->read_byte();
|
||||
uint8_t v3 = hal.dataflash->read_byte();
|
||||
uint8_t v4 = hal.dataflash->read_byte();
|
||||
uint8_t v5 = hal.dataflash->read_byte();
|
||||
uint8_t v6 = hal.dataflash->read_byte();
|
||||
uint8_t v7 = hal.dataflash->read_byte();
|
||||
hal.uart0->printf_P(PSTR("vals on page %d: %d %d %d %d %d 0x%x 0x%x\r\n"),
|
||||
i, (int) v1, (int) v2, (int) v3, (int) v4, (int) v5,
|
||||
(int) v6, (int) v7);
|
||||
}
|
||||
void two_page_readwrite() {
|
||||
hal.uart0->println("Writing simple sequence to page 1");
|
||||
hal.dataflash->start_write(1);
|
||||
hal.dataflash->write_byte(1);
|
||||
hal.dataflash->write_byte(2);
|
||||
hal.dataflash->write_byte(3);
|
||||
hal.dataflash->write_byte(4);
|
||||
hal.dataflash->write_byte(5);
|
||||
/* Fill up the rest of the page with garbage */
|
||||
for (int i = 0; i < 6; i++) {
|
||||
hal.dataflash->write_byte(0x77);
|
||||
}
|
||||
hal.dataflash->finish_write();
|
||||
|
||||
hal.scheduler->delay(100);
|
||||
readback_page(1);
|
||||
|
||||
hal.uart0->println("Writing simple sequence to page 2");
|
||||
hal.dataflash->start_write(2);
|
||||
hal.dataflash->write_byte(21);
|
||||
hal.dataflash->write_byte(22);
|
||||
hal.dataflash->write_byte(23);
|
||||
hal.dataflash->write_byte(24);
|
||||
hal.dataflash->write_byte(25);
|
||||
/* Fill up the rest of the page with garbage */
|
||||
for (int i = 0; i < 6; i++) {
|
||||
hal.dataflash->write_byte(0x77);
|
||||
}
|
||||
hal.dataflash->finish_write();
|
||||
|
||||
hal.scheduler->delay(100);
|
||||
readback_page(1);
|
||||
readback_page(2);
|
||||
hal.dataflash->start_write(3);
|
||||
hal.dataflash->write_byte(99);
|
||||
hal.dataflash->write_byte(99);
|
||||
hal.dataflash->write_byte(99);
|
||||
hal.dataflash->finish_write();
|
||||
/* NOTE: getting rid of the above finish_write
|
||||
fixup the upcoming reads: fetching page 1, 2 will work! and three is a
|
||||
faithful read (255s if erased) */
|
||||
hal.scheduler->delay(100);
|
||||
readback_page(1);
|
||||
readback_page(2);
|
||||
readback_page(3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void longtest_write() {
|
||||
// We start to write some info (sequentialy) starting from page 1
|
||||
// This is similar to what we will do...
|
||||
hal.uart0->println("After testing perform erase before using hal.dataflash->for logging!");
|
||||
hal.uart0->println("");
|
||||
hal.uart0->println("Writing to flash... wait...");
|
||||
hal.dataflash->start_write(1);
|
||||
for (int i = 0; i < 40; i++) {
|
||||
// Write 1000 packets...
|
||||
// We write packets of binary data... (without worry about nothing more)
|
||||
hal.dataflash->write_byte(0xA3);
|
||||
hal.dataflash->write_byte(0x95);
|
||||
hal.dataflash->write_word(2000 + i);
|
||||
hal.dataflash->write_word(2001 + i);
|
||||
hal.dataflash->write_word(2002 + i);
|
||||
hal.dataflash->write_word(2003 + i);
|
||||
hal.dataflash->write_dword((int32_t)i * 5000);
|
||||
hal.dataflash->write_dword((int32_t)i * 16268);
|
||||
hal.dataflash->write_byte(0xA2);// 2 bytes of checksum (example)
|
||||
hal.dataflash->write_byte(0x4E);
|
||||
hal.scheduler->delay(10);
|
||||
}
|
||||
hal.scheduler->delay(100);
|
||||
}
|
||||
|
||||
void longtest_readback()
|
||||
{
|
||||
uint8_t tmp_byte1, tmp_byte2;
|
||||
long tmp_long;
|
||||
|
||||
hal.uart0->println("Start reading page 1...");
|
||||
|
||||
hal.dataflash->start_read(1); // We start reading from page 1
|
||||
for (int i = 0; i < 40; i++) { // Read 200 packets...
|
||||
|
||||
uint8_t sync1 = hal.dataflash->read_byte();
|
||||
uint8_t sync2 = hal.dataflash->read_byte();
|
||||
|
||||
// Read 4 ints...
|
||||
int16_t w1 = hal.dataflash->read_word();
|
||||
int16_t w2 = hal.dataflash->read_word();
|
||||
int16_t w3 = hal.dataflash->read_word();
|
||||
int16_t w4 = hal.dataflash->read_word();
|
||||
|
||||
// Read 2 longs...
|
||||
int32_t l1 = hal.dataflash->read_dword();
|
||||
int32_t l2 = hal.dataflash->read_dword();
|
||||
|
||||
// Read the checksum...
|
||||
int8_t cs1 = hal.dataflash->read_byte();
|
||||
int8_t cs2 = hal.dataflash->read_byte();
|
||||
|
||||
hal.uart0->printf_P(PSTR("sync 0x%x 0x%x ints %d %d %d %d, "
|
||||
"longs %d %d, cksm %d %d\r\n"),
|
||||
(int) sync1, (int) sync2,
|
||||
w1, w2, w3, w4,
|
||||
l1, l2,
|
||||
cs1, cs2);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
hal.uart0->begin(115200);
|
||||
hal.dataflash->init(NULL);
|
||||
|
||||
hal.uart0->println("Dataflash Log Test 1.0");
|
||||
|
||||
hal.scheduler->delay(20);
|
||||
hal.uart0->print("Manufacturer:");
|
||||
hal.uart0->print((int)hal.dataflash->mfg_id());
|
||||
hal.uart0->print(",");
|
||||
hal.uart0->print((int)hal.dataflash->device_id());
|
||||
hal.uart0->println();
|
||||
|
||||
erase();
|
||||
|
||||
// two_page_readwrite();
|
||||
dbg = false;
|
||||
longtest_write();
|
||||
longtest_readback();
|
||||
|
||||
}
|
||||
void loop () {}
|
||||
|
||||
extern "C" {
|
||||
int main (void) {
|
||||
hal.init(NULL);
|
||||
setup();
|
||||
for(;;) loop();
|
||||
return 0;
|
||||
}
|
||||
}
|
1
libraries/AP_HAL_AVR/examples/DataflashTest/Makefile
Normal file
1
libraries/AP_HAL_AVR/examples/DataflashTest/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../AP_Common/Arduino.mk
|
Loading…
Reference in New Issue
Block a user