element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Benefits of Membership
    • Achievement Levels
    • Members Area
    • Personal Blogs
    • Feedback and Support
    • What's New on element14
  • Learn
    Learn
    • Learning Center
    • eBooks
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Dev Tools
    • Manufacturers
    • Raspberry Pi
    • RoadTests & Reviews
    • Avnet Boards Community
    • Product Groups
  • Store
    Store
    • Visit Your Store
    • Choose Another Store
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
Raspberry Pi
  • Products
  • More
Raspberry Pi
Blog Add external SPI Flash Memory to Raspberry Pico - 3: structure the Flash c++ class before proceding
  • Blog
  • Forum
  • Documents
  • Events
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Raspberry Pi requires membership for participation - click to join
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 2 Dec 2022 12:06 PM Date Created
  • Views 174 views
  • Likes 5 likes
  • Comments 1 comment
Related
Recommended
  • pico
  • pico_m25
  • pico_eurocard

Add external SPI Flash Memory to Raspberry Pico - 3: structure the Flash c++ class before proceding

Jan Cumps
Jan Cumps
2 Dec 2022
Add external SPI Flash Memory to Raspberry Pico - 3: structure the Flash c++ class before proceding

A projects to learn the SPI API of the RP2040 C SDK, and to use it to control an external Flash IC. In this post, I refine the m25 c++ class from previous post. 

image

What will Change and What Not?

The class initially only knew the SPI device and chip select pins. SPI and pin initialisation was done in main().

// m25.h
class m25 {
public:
  m25(spi_inst_t * spi, uint cs) : _spi(spi), _cs(cs) {}
  // ...
}

// ...

// main file:
void setSPI() {
    spi_init(M25_SPI, 1000 * 1000);
    gpio_set_function(M25_SPI_RX_PIN, GPIO_FUNC_SPI);
    gpio_set_function(M25_SPI_SCK_PIN, GPIO_FUNC_SPI);
    gpio_set_function(M25_SPI_TX_PIN, GPIO_FUNC_SPI);

    // Chip select is active-low, so we'll initialise it to a driven-high state
    gpio_init(M25_SPI_CSN_PIN);
    gpio_put(M25_SPI_CSN_PIN, 1);
    gpio_set_dir(M25_SPI_CSN_PIN, GPIO_OUT);
}


int main() {
    // ...
    setSPI();
    eeprom = new m25(M25_SPI, M25_SPI_CSN_PIN);
    // ...

Constants used in the c++ class were done with #define.

#define FLASH_CMD_RDID         0x9F

I will not (yet) create a more generic spi class, and derive from that (or use it). I hope that one day some volunteer writes a good c++ library for the RP2040. I will then piggyback on that.

Why and How?

"Why" for a few reasons, and they are all debatable.

The define turns into a private class-scope enum. I've also given it the right type.  It belongs to the class, does not have to be used outside it, and this is now also where it's defined.
I could have used a class constant definition, but chose for enum because there will be a number of them that are all related.

I've decided to let the class handle all pins. And then learn the class how to initialise them, instead of doing that in main(). Exception: I haven't told the class about the ~hold and ~write pins yet. I'll do that when (if) I introduce support for protection.

This is how the changed parts of m25.h looks like:

class m25 {
public:
  m25(spi_inst_t * spi, uint sclk, uint mosi, uint miso, uint ncs) : 
    spi(spi), sclk(sclk), mosi(mosi), miso(miso), ncs(ncs) {}
  /// ...
  uint8_t init();
  uint8_t rdid();
  uint8_t rdsr();

private:
  enum commands : uint8_t { 
    RDID = 0x9F,
    RDSR = 0x05 };
  // ...
  uint sclk, mosi, miso, ncs;

And m25.cpp:

// ...

uint8_t m25::init() {
    spi_init(spi, 1000 * 1000);
    gpio_set_function(miso, GPIO_FUNC_SPI);
    gpio_set_function(sclk, GPIO_FUNC_SPI);
    gpio_set_function(mosi, GPIO_FUNC_SPI);

    // Chip select is active-low, so we'll initialise it to a driven-high state
    gpio_init(ncs);
    gpio_put(ncs, 1);
    gpio_set_dir(ncs, GPIO_OUT);
    return 0U; 
}

uint8_t m25::rdid() {
    uint8_t retval = 0U;
    uint8_t buf[3];
    // command
    uint8_t cmdbuf[] = {
            RDID,
    };
    setDataBits(8);
    select();
    spi_write_blocking(spi, cmdbuf, 1);
    spi_read_blocking(spi, 0, buf, 1); // Manufacturer Identification
    spi_read_blocking(spi, 0, buf + sizeof buf[0], 2); // Device Identification (Memory Type || Memory Capacity)
    deselect();
    return retval;
}

uint8_t m25::rdsr() {
    uint8_t retval = 0U;
    uint8_t buf[1];
    // command
    uint8_t cmdbuf[] = {
            RDSR,
    };
    this->setDataBits(8);
    this->select();
    spi_write_blocking(spi, cmdbuf, 1);
    spi_read_blocking(spi, 0, buf, 1); // Read Status Register
    this->deselect();
    return retval;
}

The main():

int main() {
    m25 *eeprom = nullptr;
    setGPIO();

    eeprom = new m25(M25_SPI, 
      M25_SPI_SCK_PIN, M25_SPI_TX_PIN, M25_SPI_RX_PIN, M25_SPI_CSN_PIN);
    uint8_t retval;
    retval = eeprom->init();
    retval = eeprom->rdid();
    retval = eeprom->rdsr();
    delete eeprom;
    eeprom = nullptr;
// ...

As usual, the VSCode project (also directly importable into CLion - see shabaz ' comment in post 2). It contains the compiled uf2, if you're not into building from source:

spi_flash_20221202.zip

link to all posts in this series

  • Sign in to reply
  • flyingbean
    flyingbean 1 month ago

    I am going to follow your blogs on this topic. Need to make time for that.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2023 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • Facebook
  • Twitter
  • linkedin
  • YouTube