knx
ETS configurable knx-stack
samd_platform.cpp
Go to the documentation of this file.
1 #include "samd_platform.h"
2 
3 #ifdef ARDUINO_ARCH_SAMD
4 #include <knx/bits.h>
5 
6 #include <Arduino.h>
7 #ifdef USE_SAMD_EEPROM_EMULATION
8  #include <FlashAsEEPROM.h>
9 #endif
10 
11 #if KNX_FLASH_SIZE % 1024
12  #error "KNX_FLASH_SIZE must be multiple of 1024"
13 #endif
14 
15 #ifndef KNX_SERIAL
16  #define KNX_SERIAL Serial1
17 #endif
18 
20 #ifndef KNX_NO_DEFAULT_UART
21  : ArduinoPlatform(&KNX_SERIAL)
22 #endif
23 {
24 #ifndef USE_SAMD_EEPROM_EMULATION
25  init();
26 #endif
27 }
28 
29 SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s)
30 {
31 #ifndef USE_SAMD_EEPROM_EMULATION
32  init();
33 #endif
34 }
35 
37 {
38 #if defined (__SAMD51__)
39  // SAMD51 from section 9.6 of the datasheet
40 #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC)
41 #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010)
42 #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014)
43 #define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018)
44 #else
45  //#elif defined (__SAMD21E17A__) || defined(__SAMD21G18A__) || defined(__SAMD21E18A__) || defined(__SAMD21J18A__)
46  // SAMD21 from section 9.3.3 of the datasheet
47 #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
48 #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
49 #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
50 #define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
51 #endif
52 
53  return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3;
54 }
55 
57 {
58  println("restart");
59  NVIC_SystemReset();
60 }
61 
62 #ifdef USE_SAMD_EEPROM_EMULATION
63 #pragma warning "Using EEPROM Simulation"
64 uint8_t* SamdPlatform::getEepromBuffer(uint32_t size)
65 {
66  //EEPROM.begin(size);
67  if (size > EEPROM_EMULATION_SIZE)
68  fatalError();
69 
70  return EEPROM.getDataPtr();
71 }
72 
74 {
75  EEPROM.commit();
76 }
77 #else
78 
79 extern uint32_t __etext;
80 extern uint32_t __data_start__;
81 extern uint32_t __data_end__;
82 
83 static const uint32_t pageSizes[] = {8, 16, 32, 64, 128, 256, 512, 1024};
84 
85 void SamdPlatform::init()
86 {
88  _pageSize = pageSizes[NVMCTRL->PARAM.bit.PSZ];
89  _pageCnt = NVMCTRL->PARAM.bit.NVMP;
90  _rowSize = PAGES_PER_ROW * _pageSize;
91 
92  // find end of program flash and set limit to next row
93  uint32_t endEddr = (uint32_t)(&__etext + (&__data_end__ - &__data_start__)); // text + data MemoryBlock
94 #ifdef KNX_FLASH_OFFSET
95  _MemoryStart = KNX_FLASH_OFFSET;
96  _MemoryEnd = KNX_FLASH_OFFSET + KNX_FLASH_SIZE;
97 #else
98  _MemoryStart = getRowAddr(_pageSize * _pageCnt - KNX_FLASH_SIZE - 1); // 23295
99  _MemoryEnd = getRowAddr(_pageSize * _pageCnt - 1);
100 #endif
101 
102  // chosen flash size is not available anymore
103  if (_MemoryStart < endEddr)
104  {
105  println("KNX_FLASH_SIZE is not available (possible too much flash use by firmware)");
106  fatalError();
107  }
108 }
109 
111 {
112  return PAGES_PER_ROW;
113 }
114 
116 {
117  return _pageSize;
118 }
119 
121 {
122  return (uint8_t*)_MemoryStart;
123 }
124 
126 {
127  if (KNX_FLASH_SIZE <= 0)
128  return 0;
129  else
130  return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1;
131 }
132 
133 void SamdPlatform::flashErase(uint16_t eraseBlockNum)
134 {
135  noInterrupts();
136 
137  eraseRow((void*)(_MemoryStart + eraseBlockNum * _rowSize));
138  // flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
139 
140  interrupts();
141 }
142 
143 void SamdPlatform::flashWritePage(uint16_t pageNumber, uint8_t* data)
144 {
145  noInterrupts();
146 
147  write((void*)(_MemoryStart + pageNumber * _pageSize), data, _pageSize);
148  // flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize());
149 
150  interrupts();
151 }
152 
154 {
156  {
157  noInterrupts();
158 
159  eraseRow((void*)(_MemoryStart + _bufferedEraseblockNumber * _rowSize));
160  write((void*)(_MemoryStart + _bufferedEraseblockNumber * _rowSize), _eraseblockBuffer, _rowSize);
161  // flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize());
162  // flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize());
163 
164  interrupts();
165 
166  _bufferedEraseblockDirty = false;
167  }
168 }
169 
170 uint32_t SamdPlatform::getRowAddr(uint32_t flasAddr)
171 {
172  return flasAddr & ~(_rowSize - 1);
173 }
174 
175 void SamdPlatform::write(const volatile void* flash_ptr, const void* data, uint32_t size)
176 {
177  // Calculate data boundaries
178  size = (size + 3) / 4;
179  volatile uint32_t* src_addr = (volatile uint32_t*)data;
180  volatile uint32_t* dst_addr = (volatile uint32_t*)flash_ptr;
181  // volatile uint32_t *dst_addr = (volatile uint32_t *)flash_ptr;
182  // const uint8_t *src_addr = (uint8_t *)data;
183 
184  // Disable automatic page write
185  NVMCTRL->CTRLB.bit.MANW = 1;
186 
187  // Do writes in pages
188  while (size)
189  {
190  // Execute "PBC" Page Buffer Clear
191  NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC;
192 
193  while (NVMCTRL->INTFLAG.bit.READY == 0)
194  {
195  }
196 
197  // Fill page buffer
198  uint32_t i;
199 
200  for (i = 0; i < (_pageSize / 4) && size; i++)
201  {
202  *dst_addr = *src_addr;
203  src_addr++;
204  dst_addr++;
205  size--;
206  }
207 
208  // Execute "WP" Write Page
209  NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP;
210 
211  while (NVMCTRL->INTFLAG.bit.READY == 0)
212  {
213  }
214  }
215 }
216 
217 void SamdPlatform::erase(const volatile void* flash_ptr, uint32_t size)
218 {
219  const uint8_t* ptr = (const uint8_t*)flash_ptr;
220 
221  while (size > _rowSize)
222  {
223  eraseRow(ptr);
224  ptr += _rowSize;
225  size -= _rowSize;
226  }
227 
228  eraseRow(ptr);
229 }
230 
231 void SamdPlatform::eraseRow(const volatile void* flash_ptr)
232 {
233  NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2;
234  NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER;
235 
236  while (!NVMCTRL->INTFLAG.bit.READY)
237  {
238  }
239 }
240 
241 #endif
242 #endif
void println(const char *s)
uint8_t * _eraseblockBuffer
Definition: platform.h:142
NvMemoryType _memoryType
Definition: platform.h:130
int32_t _bufferedEraseblockNumber
Definition: platform.h:143
bool _bufferedEraseblockDirty
Definition: platform.h:144
virtual uint8_t * userFlashStart()
uint8_t * getEepromBuffer(uint32_t size)
virtual size_t userFlashSizeEraseBlocks()
virtual void flashErase(uint16_t eraseBlockNum)
void commitToEeprom()
uint32_t uniqueSerialNumber() override
virtual size_t flashEraseBlockSize()
void writeBufferedEraseBlock()
virtual size_t flashPageSize()
virtual void flashWritePage(uint16_t pageNumber, uint8_t *data)
@ Flash
Definition: platform.h:27
uint32_t __etext
uint32_t __data_start__
uint32_t __data_end__