Mặc cân bằng trên EEPROM của vi điều khiển


15

Ví dụ: Bảng dữ liệu cho ATtiny2313 (cũng như hầu hết các bảng dữ liệu Atmel AVR):

128 Byte Độ bền EEPROM có thể lập trình trong hệ thống: 100.000 chu kỳ ghi / xóa

Hãy tưởng tượng một chương trình chỉ cần hai byte để lưu trữ một số cấu hình, 126 byte khác bị lãng phí một cách hiệu quả. Điều tôi quan tâm là các bản cập nhật thường xuyên của hai byte cấu hình có thể làm hao mòn EEPROM của thiết bị và khiến nó trở nên vô dụng. Toàn bộ thiết bị sẽ trở nên không đáng tin cậy, bởi vì tại một thời điểm nhất định, bạn không thể theo dõi các byte nào trong EEPROM là không đáng tin cậy.

Có cách nào thông minh để thực hiện cân bằng hao mòn trên EEPROM của vi điều khiển khi bạn sử dụng hiệu quả chỉ một hoặc hai byte trong số 128 có sẵn không?


1
Nếu chu kỳ ghi 100k là một hạn chế, thay vào đó, có nên sử dụng một số công nghệ khác không? Hoặc là một cơ chế kết hợp cân bằng trong nội bộ, hoặc một cái gì đó có độ lớn hoặc độ bền cao hơn?
Anindo Ghosh

1
@AnindoGhosh Tôi chỉ không muốn lãng phí kho vi điều khiển nhỏ của mình chỉ vì làm hao mòn EEPROM do thử nghiệm của tôi một bằng chứng về khái niệm. Tôi không muốn lo lắng về byte nào tôi đã sử dụng trên một dự án trước đó khi sử dụng lại bộ điều khiển. Và thật tuyệt khi biết tôi sử dụng tối ưu phần cứng có sẵn.
jippie

3
Điều này có thể giúp: AVR101: Lưu trữ EEPROM độ bền cao
m.Alin

1
Có lẽ hãy xem câu trả lời của tôi tại stackoverflow .
JimmyB

Hãy xem loạt MSP430 FRAM của TI ... 10 ^ 13 viết !!!
geometrikal

Câu trả lời:


19

Kỹ thuật tôi thường sử dụng là tiền tố dữ liệu với số thứ tự cán 4 byte trong đó số lớn nhất biểu thị giá trị hiện tại / cuối cùng. Trong trường hợp lưu trữ 2 byte dữ liệu thực tế sẽ cung cấp tổng cộng 6 byte và sau đó tôi tạo thành một sắp xếp hàng đợi tròn, vì vậy đối với 128 byte EEPROM, nó sẽ chứa 21 mục nhập và tăng độ bền lên 21 lần.

Sau đó, khi khởi động số thứ tự lớn nhất có thể được sử dụng để xác định cả số thứ tự tiếp theo sẽ được sử dụng và đuôi hiện tại của hàng đợi. Mã giả C sau đây chứng minh, điều này giả định rằng khi lập trình ban đầu, khu vực EEPROM đã bị xóa thành các giá trị 0xFF nên tôi bỏ qua số thứ tự 0xFFFF:

struct
{
  uint32_t sequence_no;
  uint16_t my_data;
} QUEUE_ENTRY;

#define EEPROM_SIZE 128
#define QUEUE_ENTRIES (EEPROM_SIZE / sizeof(QUEUE_ENTRY))

uint32_t last_sequence_no;
uint8_t queue_tail;
uint16_t current_value;

// Called at startup
void load_queue()
{
  int i;

  last_sequence_no = 0;
  queue_tail = 0;
  current_value = 0;
  for (i=0; i < QUEUE_ENTRIES; i++)
  {
    // Following assumes you've written a function where the parameters
    // are address, pointer to data, bytes to read
    read_EEPROM(i * sizeof(QUEUE_ENTRY), &QUEUE_ENTRY, sizeof(QUEUE_ENTRY));
    if ((QUEUE_ENTRY.sequence_no > last_sequence_no) && (QUEUE_ENTRY.sequence_no != 0xFFFF))
    {
      queue_tail = i;
      last_sequence_no = QUEUE_ENTRY.sequence_no;
      current_value = QUEUE_ENTRY.my_data;
    }
  }
}

void write_value(uint16_t v)
{
  queue_tail++;
  if (queue_tail >= QUEUE_ENTRIES)
    queue_tail = 0;
  last_sequence_no++;
  QUEUE_ENTRY.sequence_no = last_sequence_no;
  QUEUE_ENTRY.my_data = v;
  // Following assumes you've written a function where the parameters
  // are address, pointer to data, bytes to write
  write_EEPROM(queue_tail * sizeof(QUEUE_ENTRY), &QUEUE_ENTRY, sizeof(QUEUE_ENTRY));
  current_value = v;
}

Đối với EEPROM nhỏ hơn, chuỗi 3 byte sẽ hiệu quả hơn, mặc dù sẽ yêu cầu một chút cắt lát thay vì sử dụng các loại dữ liệu tiêu chuẩn.


+1, Cách tiếp cận đẹp. Lưu trữ có thể được tối ưu hóa một chút bằng cách sử dụng ít byte "thẻ" hơn và có thể tùy thuộc vào một số dạng cơ chế hàm băm để cung cấp phân phối bổ sung không? Một kết hợp giữa không san lấp mặt bằng, và cách tiếp cận của bạn?
Anindo Ghosh

@AnindoGhosh, vâng tôi tin là nó có thể. Tôi thường sử dụng phương pháp này trên micros nhỏ để đơn giản hóa mã cộng với cá nhân chủ yếu sử dụng nó trên các thiết bị lớn hơn như DataFLASH. Một ý tưởng đơn giản khác cũng xuất hiện trong đầu là các số thứ tự có thể được định kỳ hạ xuống để giữ chúng ở các giá trị nhỏ hơn.
PeterJ

Ghi chú ứng dụng Atmel được đề cập bởi @ m.Alin có một đơn giản hóa thông minh: Sau khi đặt lại, sau đó có thể xem qua bộ đệm [...], tìm phần tử bộ đệm [...] cuối cùng đã thay đổi bằng cách tìm vị trí nơi sự khác biệt giữa một phần tử đệm và phần tử đệm tiếp theo lớn hơn 1 .
Jippie

Không nên write_value () đặt mục nhập tại queue_tail * sizeof (QUEUE_ENTRY)? Tôi sẽ đúng lần đầu tiên, nhưng nó không nên tiếp tục tiến lên nếu có nhiều bài viết? i không được tăng bên ngoài load_queue ().
Marshall Eubanks

2
@ DWORD32: Vâng, điều đó đúng về mặt kỹ thuật, nhưng không liên quan trong thực tế. Vào thời điểm đó, giới hạn hao mòn trên EEPROM sẽ bị vượt quá hệ số 2000!
Dave Tweed

5

Sau đây là một phương pháp sử dụng các nhóm và khoảng một byte trên mỗi thùng. Các byte xô và byte trên không nhận được cùng một lượng hao mòn. Trong ví dụ hiện tại, đã cho 128 byte EEPROM, phương thức này phân bổ 42 thùng 2 byte và 44 byte trạng thái, tăng khả năng hao mòn khoảng 42 lần.

Phương pháp:

Chia không gian địa chỉ EEPROM thành k xô, trong đó k = E / ( n +1), với n = setup-data-mảng size = kích thước nhóm và kích thước E = EEPROM (hay nói chung hơn là số EEPROM các tế bào được dành cho cấu trúc dữ liệu này).

Khởi tạo một thư mục, một mảng gồm m byte được đặt thành k , với m = En · k . Khi thiết bị của bạn khởi động, nó sẽ đọc qua thư mục cho đến khi tìm thấy mục hiện tại, đó là một byte không bằng k . [Nếu tất cả các mục nhập thư mục bằng k , hãy khởi tạo mục nhập thư mục đầu tiên thành 0 và tiếp tục từ đó.]

Khi mục nhập thư mục hiện tại chứa j , xô j chứa dữ liệu hiện tại. Khi bạn cần viết một mục nhập dữ liệu thiết lập mới, bạn lưu trữ j +1 vào mục nhập thư mục hiện tại; nếu điều đó làm cho nó bằng k , hãy khởi tạo mục nhập thư mục tiếp theo thành 0 và tiếp tục từ đó.

Lưu ý rằng thư mục byte nhận được khoảng cùng một lượng mặc như xô byte vì 2 · k > mk .

(Tôi đã điều chỉnh câu trả lời trên từ câu trả lời của tôi cho câu hỏi Arduino SE 34189 , Làm thế nào để tăng tuổi thọ của EEPROM ? .)


2

Tôi đã sử dụng số thứ tự cán cho cái này (tương tự như câu trả lời của Peter). Số thứ tự thực sự có thể chỉ là 1 bit, cung cấp số phần tử trong tín hiệu là số lẻ. Đầu và đuôi sau đó được đánh dấu bằng 2 hoặc 1 giây liên tiếp

Ví dụ: nếu muốn cuộn qua 5 phần tử, số thứ tự sẽ là:

{01010} (ghi vào 0) {11010} (ghi vào 1) {10010} (ghi vào 2) {10110} (ghi vào 3) {10100} (ghi vào 4) {10101} (ghi vào 5)


1

Có một vài tùy chọn tùy thuộc vào loại EEPROM bạn có và kích thước dữ liệu của bạn.

  1. Nếu EEPROM của bạn có các trang có thể xóa riêng lẻ và bạn sử dụng 1 trang (hoặc nhiều hơn), chỉ cần giữ tất cả các trang bị xóa trừ những trang đang sử dụng và sử dụng lại các trang theo cách tuần hoàn.

  2. Nếu bạn chỉ sử dụng một phần của trang phải xóa cùng một lúc, hãy phân vùng trang đó thành các mục nhập dữ liệu. Sử dụng một mục sạch mỗi khi bạn viết và xóa một khi bạn hết các mục sạch.

Sử dụng bit "bẩn" để phân biệt giữa các mục sạch và bẩn nếu cần thiết (thông thường, bạn có ít nhất một byte được đảm bảo khác với 0xFF, có thể được sử dụng để theo dõi các mục bẩn).

Nếu thư viện EEPROM của bạn không hiển thị chức năng xóa (như Arduino), thì đây là một mẹo gọn cho thuật toán # 2: vì mục nhập EEPROM đầu tiên của bạn luôn được sử dụng, bạn có thể xác định giá trị của bit "bẩn" bằng cách đọc nó. Sau đó, khi bạn hết các mục sạch, bạn chỉ cần bắt đầu lại từ mục đầu tiên, đảo ngược bit "bẩn" và phần còn lại của các mục nhập của bạn sẽ tự động được đánh dấu là "sạch".

Số thứ tự và danh mục là một sự lãng phí không gian trừ khi bạn muốn có thể theo dõi các trang xấu hoặc cập nhật các phần khác nhau của dữ liệu EEPROM của bạn một cách độc lập.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.