M25P16.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017, James Jackson
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "M25P16.h"
33 
34 #include "revo_f4.h"
35 
37 
38 void M25P16::init(SPI *_spi)
39 {
40  // Set up the SPI peripheral
41  spi_ = _spi;
42  spi_->set_divisor(2);
43 
44  // Set up the clock select pin
46 }
47 
49 {
50  // Send the address byte
51  spi_->enable(cs_);
53 
54  // Push a garbage byte to clock out the status
55  uint8_t status = spi_->transfer_byte(0xFF);
56  spi_->disable(cs_);
57  return status;
58 }
59 
60 bool M25P16::read_config(uint8_t *data, uint32_t len)
61 {
62  // Send the read data command, with address 0
63  // Then clock out the right number of bytes
64  spi_->enable(cs_);
65  uint8_t addr[4] = {READ_DATA, 0, 0, 0};
66  spi_->transfer(addr, 4, nullptr);
67  while (spi_->is_busy())
68  {
69  }
70  spi_->transfer(nullptr, len, data);
71  while (spi_->is_busy())
72  ;
73  spi_->disable(cs_);
74  return true;
75 }
76 
77 bool M25P16::write_config(const uint8_t *data, const uint32_t len)
78 {
79  // Calculate the correct number of pages to store the config
80  num_pages_for_config_ = len / 256;
81  if (len % 256 != 0)
82  num_pages_for_config_++; // We need an extra partial page
83 
84  // Enable the write
86 
87  // Make sure we can erase (WEL bit is set)
88  uint8_t status = get_status();
89  if (!(status & STATUS_WEL_BIT))
90  return false;
91 
92  // Erase Sector (There is really no way around this, we have to erase the entire sector
93  uint8_t sector_addr[4] = {SECTOR_ERASE, 0, 0, 0};
94  spi_->transfer(sector_addr, 4, NULL, &cs_);
95  while (spi_->is_busy())
96  {
97  }
98 
99  // Wait for Sector Erase to complete
100  bool WIP = true;
101  do
102  {
103  status = get_status();
104  if ((status & STATUS_WIP_BIT) == 0x00)
105  WIP = false;
106  } while (WIP);
107 
108  // Program the data
109  for (uint32_t i = 0; i < num_pages_for_config_; i++)
110  {
111  // Re-Enable the write (the WEL bit is reset after each program completion)
113 
114  // Make sure that the WEL bit has been set, so we can write
115  status = get_status();
116 
117  // Figure out how much of this page we are going to use
118  uint16_t page_len = 256;
119  if (i == num_pages_for_config_ - 1)
120  page_len = len % 256; // If this is last page, then we write the partial
121 
122  // Send the PAGE_PROGRAM command with the right address
123  spi_->enable(cs_);
124  uint8_t addr[4] = {PAGE_PROGRAM, static_cast<uint8_t>(i >> 8), static_cast<uint8_t>(i & 0xFF), 0};
125  spi_->transfer(addr, 4, NULL, NULL);
126  while (spi_->is_busy())
127  {
128  } // Wait for the address to clear
129 
130  // Transfer the data
131  spi_->write(&data[256 * i], page_len);
132  while (spi_->is_busy())
133  {
134  } // Wait for the page to write
135  spi_->disable(cs_);
136 
137  // Wait for the page program to happen
138  WIP = true;
139  do
140  {
141  status = get_status();
142  if ((status & STATUS_WIP_BIT) == 0x00)
143  WIP = false;
144  } while (WIP);
145  }
146 
147  // Disable the write
149  return true;
150 }
M25P16()
Definition: M25P16.cpp:36
Definition: spi.h:37
void enable(GPIO &cs)
Definition: spi.cpp:150
bool transfer(uint8_t *out_data, uint32_t num_bytes, uint8_t *in_data, GPIO *cs=NULL, void(*cb)(void)=NULL)
Definition: spi.cpp:206
bool write(const uint8_t *out_data, uint32_t num_bytes, GPIO *cs=NULL)
Definition: spi.cpp:191
static volatile uint8_t * status
Definition: drv_i2c.c:102
GPIO cs_
Definition: M25P16.h:40
uint32_t num_pages_for_config_
Definition: M25P16.h:44
void init(GPIO_TypeDef *BasePort, uint16_t pin, gpio_mode_t mode)
Definition: gpio.cpp:34
bool read_config(uint8_t *data, uint32_t len)
Definition: M25P16.cpp:60
static volatile uint8_t addr
Definition: drv_i2c.c:95
bool write_config(const uint8_t *data, const uint32_t len)
Definition: M25P16.cpp:77
#define FLASH_CS_PIN
Definition: revo_f4.h:112
bool is_busy()
Definition: spi.h:51
uint8_t get_status()
Definition: M25P16.cpp:48
SPI * spi_
Definition: M25P16.h:39
#define FLASH_CS_GPIO
Definition: revo_f4.h:111
uint8_t transfer_byte(uint8_t data, GPIO *cs=NULL)
Definition: spi.cpp:160
void init(SPI *_spi)
Definition: M25P16.cpp:38
void set_divisor(uint16_t new_divisor)
Definition: spi.cpp:109
#define NULL
Definition: usbd_def.h:50
void disable(GPIO &cs)
Definition: spi.cpp:155


rosflight_firmware
Author(s): Daniel Koch , James Jackson
autogenerated on Thu Apr 15 2021 05:07:46