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 #include "revo_f4.h"
34 
36 
37 void M25P16::init(SPI *_spi)
38 {
39  // Set up the SPI peripheral
40  spi_ = _spi;
41  spi_->set_divisor(2);
42 
43  // Set up the clock select pin
45 }
46 
48 {
49  // Send the address byte
50  spi_->enable(cs_);
52 
53  // Push a garbage byte to clock out the status
54  uint8_t status = spi_->transfer_byte(0xFF);
55  spi_->disable(cs_);
56  return status;
57 }
58 
59 bool M25P16::read_config(uint8_t *data, uint32_t len)
60 {
61  // Send the read data command, with address 0
62  // Then clock out the right number of bytes
63  spi_->enable(cs_);
64  uint8_t addr[4] = {READ_DATA, 0, 0, 0};
65  spi_->transfer(addr, 4, nullptr);
66  while (spi_->is_busy()) {}
67  spi_->transfer(nullptr, len, data);
68  while (spi_->is_busy());
69  spi_->disable(cs_);
70  return true;
71 }
72 
73 bool M25P16::write_config(const uint8_t *data, const uint32_t len)
74 {
75  // Calculate the correct number of pages to store the config
76  num_pages_for_config_ = len / 256;
77  if (len % 256 != 0)
78  num_pages_for_config_ ++; // We need an extra partial page
79 
80  // Enable the write
82 
83  // Make sure we can erase (WEL bit is set)
84  uint8_t status = get_status();
85  if (!(status & STATUS_WEL_BIT))
86  return false;
87 
88  // Erase Sector (There is really no way around this, we have to erase the entire sector
89  uint8_t sector_addr[4] = {SECTOR_ERASE, 0, 0, 0};
90  spi_->transfer(sector_addr, 4, NULL, &cs_);
91  while (spi_->is_busy()) {}
92 
93  // Wait for Sector Erase to complete
94  bool WIP = true;
95  do
96  {
97  status = get_status();
98  if ((status & STATUS_WIP_BIT) == 0x00)
99  WIP = false;
100  }
101  while (WIP);
102 
103  // Program the data
104  for (uint32_t i = 0; i < num_pages_for_config_; i++)
105  {
106  // Re-Enable the write (the WEL bit is reset after each program completion)
108 
109  // Make sure that the WEL bit has been set, so we can write
110  status = get_status();
111 
112  // Figure out how much of this page we are going to use
113  uint16_t page_len = 256;
114  if (i == num_pages_for_config_ - 1)
115  page_len = len % 256; // If this is last page, then we write the partial
116 
117  // Send the PAGE_PROGRAM command with the right address
118  spi_->enable(cs_);
119  uint8_t addr[4] = {PAGE_PROGRAM, static_cast<uint8_t>(i >> 8), static_cast<uint8_t>(i & 0xFF), 0};
120  spi_->transfer(addr, 4, NULL, NULL);
121  while (spi_->is_busy()) {} // Wait for the address to clear
122 
123  // Transfer the data
124  spi_->write(&data[256*i], page_len);
125  while (spi_->is_busy()) {} // Wait for the page to write
126  spi_->disable(cs_);
127 
128  // Wait for the page program to happen
129  WIP = true;
130  do
131  {
132  status = get_status();
133  if ((status & STATUS_WIP_BIT) == 0x00)
134  WIP = false;
135  }
136  while (WIP);
137  }
138 
139  // Disable the write
141  return true;
142 }
M25P16()
Definition: M25P16.cpp:35
Definition: spi.h:38
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:207
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:59
static volatile uint8_t addr
Definition: drv_i2c.c:95
bool write_config(const uint8_t *data, const uint32_t len)
Definition: M25P16.cpp:73
#define FLASH_CS_PIN
Definition: revo_f4.h:128
bool is_busy()
Definition: spi.h:54
uint8_t get_status()
Definition: M25P16.cpp:47
SPI * spi_
Definition: M25P16.h:39
#define FLASH_CS_GPIO
Definition: revo_f4.h:127
uint8_t transfer_byte(uint8_t data, GPIO *cs=NULL)
Definition: spi.cpp:160
void init(SPI *_spi)
Definition: M25P16.cpp:37
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 Wed Jul 3 2019 19:59:24