Chihiro H
/
Microchip23LC1024_demo
Microchip SPI SRAM 23LC1024 demo
main.cpp
- Committer:
- discypus
- Date:
- 2015-11-09
- Revision:
- 3:b585283f5932
- Parent:
- 2:e0d7ea47d2a5
File content as of revision 3:b585283f5932:
/* * sample for Microchip 23LC1024 (SRAM, SPI 20MHz) */ #include "mbed.h" #define DWT_CONTROL ((volatile uint32_t *)0xE0001000) #define DWT_CYCCNT ((volatile uint32_t *)0xE0001004) #define SCB_DEMCR ((volatile uint32_t *)0xE000EDFC) static inline void enableDwtCyccnt() { // const uint32_t NOCYCCNT = 1u << 25; // 1:CYCCNT is NOT support const uint32_t TRCENA = 1u << 24; // enable DWT const uint32_t CYCCNTENA = 1u << 0; // enable counter // if (*DWT_CONTROL & NOCYCCNT) { // F401REではsetされていたが、動作する。 *SCB_DEMCR |= TRCENA; *DWT_CONTROL |= CYCCNTENA; *DWT_CYCCNT = 0; // reset the counter // } else { // NOT supported DWT_CYCCNT // pc.printf("NOT supported DWT_CYCCNT\r\n"); // } } static inline uint32_t getDwtCyccnt(void) { return *DWT_CYCCNT; } /** Serial port for DEBUG */ Serial pc(USBTX, USBRX); DigitalIn user_button(USER_BUTTON); /** */ SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK); /** */ DigitalOut cs(SPI_CS); /** * USERボタンが押されるまで待つ。 */ void wait_until_user_button_pressed() { while (user_button) { __nop(); } pc.printf("USER button is pressed\r\n"); wait(0.2); } /** * 動作確認のために、spiオブジェクトを直接使って読み書きする。 * @pre SPI初期化ずみであること。 */ void try_single_byte_access() { const uint32_t address = 0u; const uint8_t address_high = (address >> (8 * 2)) & 0xFFu; const uint8_t address_mid = (address >> (8 * 1)) & 0xFFu; const uint8_t address_low = (address >> (8 * 0)) & 0xFFu; const uint8_t command_write = 0x02u; const uint8_t command_read = 0x03u; const uint8_t data = 0x55; static uint32_t cpuCounter[100] = {}; size_t counterIndex = 0; enableDwtCyccnt(); // 1byte write cpuCounter[counterIndex++] = getDwtCyccnt(); cs = 0; cpuCounter[counterIndex++] = getDwtCyccnt(); spi.write(command_write); cpuCounter[counterIndex++] = getDwtCyccnt(); spi.write(address_high); cpuCounter[counterIndex++] = getDwtCyccnt(); spi.write(address_mid); cpuCounter[counterIndex++] = getDwtCyccnt(); spi.write(address_low); cpuCounter[counterIndex++] = getDwtCyccnt(); spi.write(data); cpuCounter[counterIndex++] = getDwtCyccnt(); // 3:CS Hold Time 50ns(min)=1cycle(20MHz) cs = 1; cpuCounter[counterIndex++] = getDwtCyccnt(); // 1byte read cs = 0; cpuCounter[counterIndex++] = getDwtCyccnt(); // 2:CS setup time 25ns(min) spi.write(command_read); cpuCounter[counterIndex++] = getDwtCyccnt(); spi.write(address_high); cpuCounter[counterIndex++] = getDwtCyccnt(); spi.write(address_mid); cpuCounter[counterIndex++] = getDwtCyccnt(); spi.write(address_low); cpuCounter[counterIndex++] = getDwtCyccnt(); const uint8_t value = spi.write(0); cpuCounter[counterIndex++] = getDwtCyccnt(); // 3:CS Hold Time 50ns(min) cs = 1; cpuCounter[counterIndex++] = getDwtCyccnt(); pc.printf("single byte access test: result\r\n"); pc.printf(" write: %02x -> read: %02x\r\n", data, value); pc.printf("CPU Cycle counter\r\n"); for (int i = 1; i < counterIndex; i++) { const float ns = (cpuCounter[i] - cpuCounter[i - 1]) / (float)SystemCoreClock * 1.0e9; pc.printf(" %02d = %.3f\r\n", i, ns); } } /* * SPI COMMAND (Microchip 23LC1024, 23K256 SPI SRAM) */ enum Microchip23LC1024Commnd { READ = 0x03u, WRITE = 0x02u, EDIO = 0x3bu, EQIO = 0x38u, RSTIO = 0xffu, RDMR = 0x05u, WRMR = 0x01u, }; /** SRAM Mode (Microchip 23LC1024, 23K256 SPI SRAM) */ enum Microchip23LC1024Mode { MODE_MASK = 0xc0u, BYTE = 0x00u, SEQUENTIAL = 0x40u, // default operation PAGE = 0x80u, RESERVED = 0xC0u, }; /** * assert CS */ inline void assert_CS() { cs = 0; } /** * negate CS */ inline void negate_CS() { cs = 1; } /** * モードレジスタ読みだし * @return レジスタ値 */ inline uint8_t read_mode_register() { assert_CS(); spi.write(RDMR); const uint8_t mode = spi.write(0x00); negate_CS(); return mode; } /** * モードレジスタ書き込み * @param[in] mode */ inline void write_mode_register(const uint8_t mode) { assert_CS(); spi.write(WRMR); spi.write(mode); negate_CS(); } /** * モードを切り替える。 * @param[in] mode モード * @return 切替前のモード * @invariant レジスタ中のモード以外のフラグは変更しない。 */ inline uint8_t change_mode(const unsigned int next_mode) { const uint8_t previous_register = read_mode_register(); const uint8_t previous_mode = previous_register & MODE_MASK; if (next_mode != previous_mode) { const uint8_t next_register = (previous_register & ~MODE_MASK) | uint8_t(next_mode); write_mode_register(next_register); } return previous_mode; } /** * 1byte read * @param[in] address アドレス 24bit * @return データ */ uint8_t read_byte(const uint32_t address) { const uint8_t address_high = (address >> (8 * 2)) & 0xFFu; const uint8_t address_mid = (address >> (8 * 1)) & 0xFFu; const uint8_t address_low = (address >> (8 * 0)) & 0xFFu; assert_CS(); spi.write(READ); spi.write(address_high); spi.write(address_mid); spi.write(address_low); const uint8_t data = spi.write(0); negate_CS(); return data; } /** * 1byte write * @param[in] address アドレス 24bit * @param[in] data データ */ void write_byte(const uint32_t address, const uint8_t data) { const uint8_t address_high = (address >> (8 * 2)) & 0xFFu; const uint8_t address_mid = (address >> (8 * 1)) & 0xFFu; const uint8_t address_low = (address >> (8 * 0)) & 0xFFu; assert_CS(); spi.write(WRITE); spi.write(address_high); spi.write(address_mid); spi.write(address_low); spi.write(data); negate_CS(); } /** * 連続読み出し * @pre sequentialモードかpageモードに切り替えていること。 */ void read_bytes(const uint32_t address, uint8_t __restrict data[], const uint32_t size) { const uint8_t address_high = (address >> (8 * 2)) & 0xFFu; const uint8_t address_mid = (address >> (8 * 1)) & 0xFFu; const uint8_t address_low = (address >> (8 * 0)) & 0xFFu; assert_CS(); spi.write(READ); spi.write(address_high); spi.write(address_mid); spi.write(address_low); for (uint32_t i = 0; i < size; ++i) { data[i] = spi.write(0x00); } negate_CS(); } /** * 連続書き込み * @pre sequentialモードかpageモードに切り替えていること。 */ void write_bytes(const uint32_t address, const uint8_t __restrict data[], const uint32_t size) { const uint8_t address_high = (address >> (8 * 2)) & 0xFFu; const uint8_t address_mid = (address >> (8 * 1)) & 0xFFu; const uint8_t address_low = (address >> (8 * 0)) & 0xFFu; assert_CS(); spi.write(WRITE); spi.write(address_high); spi.write(address_mid); spi.write(address_low); for (uint32_t i = 0; i < size; ++i) { spi.write(data[i]); } negate_CS(); } /* * */ /** 動作確認用 SPI buffer */ uint8_t buf[256] = {}; /** * byteアクセスを複数回実行して、照合する */ void try_byte_access() { const uint8_t size = 16; // write data for (int i = 0; i < size; i++) { write_byte(i, i); } // read data for (int i = 0; i < size; i++) { buf[i] = read_byte(i); } // show data (to SERIAL) pc.printf("byte access test: result\r\n"); for (int i = 0; i < size; i++) { pc.printf(" %04x : %02x %s\r\n", i, buf[i], (buf[i] ==i)?"OK":"BAD"); } } /** * pageアクセスを実行して、照合する */ void try_page_access() { const uint32_t address = 0x1000; const uint32_t page_size = 32; // write for (uint32_t i = 0; i < page_size; ++i) { buf[i] = i; } write_bytes(address, buf, page_size); // read for (uint32_t i = 0; i < page_size; ++i) { buf[i] = 0; } read_bytes(address, buf, page_size); // show data (to SERIAL) pc.printf("page access test: result\r\n"); for (int i = 0; i < page_size; i++) { pc.printf(" %04x : %02x %s\r\n", address + i, buf[i], (buf[i] ==i)?"OK":"BAD"); } } /** * sequentialアクセスを実行して、照合する */ void try_sequential_access() { const uint32_t address = 0x2000; const uint32_t size = 256; // write for (uint32_t i = 0; i < size; ++i) { buf[i] = i; } write_bytes(address, buf, size); // read for (uint32_t i = 0; i < size; ++i) { buf[i] = 0; } read_bytes(address, buf, size); // show data (to SERIAL) pc.printf("sequential access test: result\r\n"); for (int i = 0; i < size; i++) { pc.printf(" %04x : %02x %s\r\n", address + i, buf[i], (buf[i] ==i)?"OK":"BAD"); } } /** * 動作確認用。TODO: テストコードにすること。 */ int main() { pc.baud(115200); pc.printf("CPU SystemCoreClock is %.2f MHz\r\n", (float)SystemCoreClock/1.0e6f); // initialize SPI spi.format(8, 0); // 8bit, mode=0 spi.frequency(20 * 1000 * 1000); // max 20MHz negate_CS(); // read mode pc.printf("\r\nread mode register\r\n"); const uint8_t mode = read_mode_register(); pc.printf(" mode register = %02x\r\n", mode); // test pc.printf("\r\npush user button to start: try_single_byte_access\r\n"); wait_until_user_button_pressed(); try_single_byte_access(); pc.printf("\r\npush user button to start: try_sequential_access (default)\r\n"); wait_until_user_button_pressed(); try_sequential_access(); pc.printf("\r\npush user button to start: try_byte_access\r\n"); wait_until_user_button_pressed(); change_mode(BYTE); try_byte_access(); pc.printf("\r\npush user button to start: try_page_access\r\n"); wait_until_user_button_pressed(); change_mode(PAGE); try_page_access(); pc.printf("\r\npush user button to start: try_sequential_access\r\n"); wait_until_user_button_pressed(); change_mode(SEQUENTIAL); try_sequential_access(); pc.printf("\r\nTEST END\r\n\r\n"); for(;;) { } }