/* driver for RAMTRON FRAM persistent memory devices. These are used for parameter and waypoint storage on most FMUv1, FMUv2, FMUv3 and FMUv4 boards */ #include "AP_RAMTRON.h" extern const AP_HAL::HAL &hal; // register numbers #define RAMTRON_RDID 0x9f #define RAMTRON_READ 0x03 #define RAMTRON_RDSR 0x05 #define RAMTRON_WREN 0x06 #define RAMTRON_WRITE 0x02 /* list of supported devices. Thanks to NuttX ramtron driver */ const AP_RAMTRON::ramtron_id AP_RAMTRON::ramtron_ids[] = { { 0x21, 0x00, 16, 2}, // FM25V01 { 0x21, 0x08, 16, 2}, // FM25V01A { 0x22, 0x00, 32, 2}, // FM25V02 { 0x22, 0x08, 32, 2}, // FM25V02A { 0x22, 0x01, 32, 2}, // FM25VN02 { 0x23, 0x00, 64, 2}, // FM25V05 { 0x23, 0x01, 64, 2}, // FM25VN05 { 0x24, 0x00, 128, 3}, // FM25V10 { 0x24, 0x01, 128, 3}, // FM25VN10 { 0x25, 0x08, 256, 3}, // FM25V20A { 0x26, 0x08, 512, 3}, // CY15B104Q { 0x27, 0x03, 128, 3}, // MB85RS1MT { 0x05, 0x09, 32, 3}, // B85RS256B }; // initialise the driver bool AP_RAMTRON::init(void) { dev = hal.spi->get_device("ramtron"); if (!dev) { return false; } WITH_SEMAPHORE(dev->get_semaphore()); struct rdid { uint8_t manufacturer[6]; uint8_t memory; uint8_t id1; uint8_t id2; } rdid; if (!dev->read_registers(RAMTRON_RDID, (uint8_t *)&rdid, sizeof(rdid))) { return false; } for (uint8_t i=0; iprintf("Unknown RAMTRON manufacturer=%02x memory=%02x id1=%02x id2=%02x\n", rdid.manufacturer[0], rdid.memory, rdid.id1, rdid.id2); return false; } /* send a command and offset */ void AP_RAMTRON::send_offset(uint8_t cmd, uint32_t offset) { if (ramtron_ids[id].addrlen == 3) { uint8_t b[4] = { cmd, uint8_t((offset>>16)&0xFF), uint8_t((offset>>8)&0xFF), uint8_t(offset&0xFF) }; dev->transfer(b, sizeof(b), nullptr, 0); } else /* len 2 */ { uint8_t b[3] = { cmd, uint8_t((offset>>8)&0xFF), uint8_t(offset&0xFF) }; dev->transfer(b, sizeof(b), nullptr, 0); } } // read from device bool AP_RAMTRON::read(uint32_t offset, uint8_t *buf, uint32_t size) { const uint8_t maxread = 128; while (size > maxread) { if (!read(offset, buf, maxread)) { return false; } offset += maxread; buf += maxread; size -= maxread; } WITH_SEMAPHORE(dev->get_semaphore()); dev->set_chip_select(true); send_offset(RAMTRON_READ, offset); // get data dev->transfer(nullptr, 0, buf, size); dev->set_chip_select(false); return true; } // write to device bool AP_RAMTRON::write(uint32_t offset, const uint8_t *buf, uint32_t size) { WITH_SEMAPHORE(dev->get_semaphore()); // write enable uint8_t r = RAMTRON_WREN; dev->transfer(&r, 1, nullptr, 0); dev->set_chip_select(true); send_offset(RAMTRON_WRITE, offset); dev->transfer(buf, size, nullptr, 0); dev->set_chip_select(false); return true; }