สวม leveling บน EEPROM ของไมโครคอนโทรลเลอร์


15

ตัวอย่างเช่น: แผ่นข้อมูลสำหรับ ATtiny2313 (เช่นเดียวกับเอกสารข้อมูล Atmel AVR ส่วนใหญ่) ระบุ:

ความทนทาน EEPROM ที่ตั้งโปรแกรมได้ในระบบ 128 Bytes: 100,000 รอบการเขียน / ลบ

ลองนึกภาพโปรแกรมที่ต้องการเพียงสองไบต์ในการจัดเก็บการกำหนดค่าบางส่วนอื่น ๆ 126 ไบต์เสียอย่างมีประสิทธิภาพ สิ่งที่เกี่ยวข้องกับฉันคือการอัพเดตปกติของสองไบต์การกำหนดค่าอาจทำให้ EEPROM ของอุปกรณ์เสื่อมสภาพและทำให้ใช้งานไม่ได้ อุปกรณ์ทั้งหมดจะไม่น่าเชื่อถือเพราะในช่วงเวลาหนึ่งคุณไม่สามารถติดตามได้ว่าไบต์ใดใน EEPROM ที่ไม่น่าเชื่อถือ

มีวิธีที่ชาญฉลาดในการสวมระดับบน EEPROM ของไมโครคอนโทรลเลอร์เมื่อคุณใช้เพียงหนึ่งหรือสองไบต์จาก 128 ที่มีอยู่อย่างมีประสิทธิภาพหรือไม่


1
ถ้ารอบการเขียนขนาด 100k เป็นข้อ จำกัด มันจะสมเหตุสมผลไหมที่จะใช้เทคโนโลยีอื่นแทน มีกลไกที่รวมการปรับระดับภายในหรือบางสิ่งบางอย่างที่มีลำดับความสำคัญหรือความอดทนมากกว่า
Anindo Ghosh

1
@AnindoGhosh ฉันไม่ต้องการที่จะเสียสต็อกของไมโครคอนโทรลเลอร์ขนาดเล็กของฉันเพียงเพราะ EEPROM เสื่อมสภาพเนื่องจากการทดสอบของฉันพิสูจน์แนวคิด ฉันไม่ต้องการที่จะกังวลว่าฉันใช้ไบต์ใดในโปรเจ็กต์ก่อนหน้าเมื่อใช้คอนโทรลเลอร์อีกครั้ง และมันก็รู้สึกดีที่รู้ว่าฉันใช้ประโยชน์สูงสุดจากฮาร์ดแวร์ที่มีอยู่
jippie

3
สิ่งนี้อาจช่วยได้: AVR101: EEPROM Storage ที่มีความทนทานสูง
m.Alin

1
อาจจะมีลักษณะที่เป็นคำตอบของฉันที่StackOverflow
JimmyB

ดูซีรี่ส์ FRAM MSP430 ของ TI ... 10 ^ 13 เขียน !!!
geometrikal

คำตอบ:


19

เทคนิคที่ฉันใช้ตามปกติคือนำหน้าข้อมูลด้วยหมายเลขลำดับการหมุน 4 ไบต์ซึ่งตัวเลขที่ใหญ่ที่สุดแสดงถึงค่าล่าสุด / ปัจจุบัน ในกรณีของการจัดเก็บข้อมูลจริง 2 ไบต์ที่จะให้ผลรวม 6 ไบต์แล้วฉันจัดรูปแบบการจัดคิวแบบวงกลมดังนั้นสำหรับ EEPROM 128 ไบต์ของ EEPROM จะมี 21 รายการและเพิ่มความทนทาน 21 ครั้ง

จากนั้นเมื่อทำการบู๊ตหมายเลขลำดับที่ใหญ่ที่สุดสามารถใช้เพื่อกำหนดหมายเลขลำดับถัดไปที่จะใช้และส่วนท้ายปัจจุบันของคิว รหัสหลอก C ต่อไปนี้แสดงให้เห็นว่านี่เป็นการสันนิษฐานว่าเมื่อการตั้งโปรแกรมเริ่มต้นพื้นที่ EEPROM ถูกลบไปเป็นค่า 0xFF ดังนั้นฉันจึงไม่สนใจหมายเลขลำดับ 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;
}

สำหรับ EEPROM ขนาดเล็กลำดับ 3 ไบต์จะมีประสิทธิภาพมากขึ้นแม้ว่าจะต้องใช้บิตของการแบ่งส่วนเล็กน้อยแทนที่จะใช้ชนิดข้อมูลมาตรฐาน


+1, แนวทางที่ดี สามารถเพิ่มประสิทธิภาพการจัดเก็บเล็กน้อยโดยใช้ "แท็ก" น้อยไบต์และอาจขึ้นอยู่กับรูปแบบของกลไกถังฝากข้อมูลเพื่อให้การกระจายเพิ่มเติม? ลูกผสมระหว่างไม่มีการปรับระดับและวิธีการของคุณ?
Anindo Ghosh

@ AnindoGhosh ใช่ฉันเชื่อว่าทำได้ ปกติฉันจะใช้วิธีนี้กับ micros ขนาดเล็กเพื่อความง่ายของโค้ดและโดยส่วนตัวแล้วส่วนใหญ่จะใช้กับอุปกรณ์ขนาดใหญ่เช่น DataFLASH แนวคิดง่ายๆอีกข้อหนึ่งที่นึกได้คือตัวเลขลำดับอาจถูกลดลงเป็นระยะเพื่อให้พวกเขามีค่าน้อยลง
PeterJ

แอปพลิเคชัน Atmel ที่กล่าวถึงโดย @ m.Alin มีการทำให้เข้าใจง่ายแบบอัจฉริยะ: หลังจาก RESET จะสามารถมองผ่านบัฟเฟอร์ [... ] การค้นหาองค์ประกอบบัฟเฟอร์ [... ] ล่าสุดจะเปลี่ยนไปโดยการค้นหาตำแหน่งที่ ความแตกต่างระหว่างองค์ประกอบบัฟเฟอร์และองค์ประกอบบัฟเฟอร์ต่อไปคือขนาดใหญ่กว่า 1
jippie

ไม่ควร write_value () ใส่รายการที่ queue_tail * sizeof (QUEUE_ENTRY)? ฉันจะแก้ไขให้ถูกต้องในครั้งแรก แต่ไม่ควรดำเนินการต่อหากมีหลายการเขียน? i ไม่ได้ถูกเพิ่มค่าภายนอก load_queue ()
Marshall Eubanks

2
@ DWORD32: ใช่มันถูกต้องทางเทคนิค แต่ไม่เกี่ยวข้องในทางปฏิบัติ เมื่อถึงเวลาที่กำหนดขีด จำกัด การสึกหรอบน EEPROM จะเกิน 2000 เท่า!
Dave Tweed

5

ต่อไปนี้เป็นวิธีการที่ใช้ที่เก็บข้อมูลและประมาณหนึ่งไบต์ค่าใช้จ่ายต่อที่ฝากข้อมูล ไบต์ที่ฝากข้อมูลและไบต์ค่าใช้จ่ายรับเกี่ยวกับจำนวนเท่ากันของการสึกหรอ ในตัวอย่างในมือ 128 EEPROM ที่กำหนดวิธีการนี้จัดสรร 42 2 ไบต์ถังและ 44 สถานะไบต์เพิ่มความสามารถในการสึกหรอประมาณ 42 เท่า

วิธี:

แบ่งการกำหนดพื้นที่ EEPROM ออกเป็นk buckets โดยที่k = ⌊ E / ( n +1) ⌋โดยมีn = ขนาดเซ็ตอัพ data-array = ขนาด bucket และE = ขนาด EEPROM (หรือโดยทั่วไปแล้วจำนวน EEPROM เซลล์ที่จะอุทิศให้กับโครงสร้างข้อมูลนี้)

เริ่มต้นไดเรกทอรีอาร์เรย์ของไบต์มทุกชุดจะkกับm = En · k เมื่ออุปกรณ์ของคุณจะเริ่มขึ้นก็อ่านผ่านไดเรกทอรีจนกว่าจะพบรายการในปัจจุบันซึ่งเป็นไบต์ไม่เท่ากับk [หากรายการไดเรกทอรีทั้งหมดเท่ากับkให้เริ่มต้นรายการไดเรกทอรีแรกเป็น 0 และดำเนินการต่อจากที่นั่น]

เมื่อรายการไดเร็กทอรีปัจจุบันมีj , bucket jมีข้อมูลปัจจุบัน เมื่อคุณต้องการเขียนรายการการตั้งค่าข้อมูลใหม่คุณเก็บj +1 ลงในรายการไดเรกทอรีปัจจุบัน ถ้านั่นทำให้มันเท่ากับk , เริ่มต้นรายการไดเรกทอรีถัดไปเป็น 0 และไปจากที่นั่น

โปรดทราบว่าไบต์ไดเรกทอรีได้รับเกี่ยวกับจำนวนเดียวกันของการสวมใส่เป็นถังไบต์เพราะ 2 · k > เมตร ≥ k

(ผมดัดแปลงมาข้างต้นจากคำตอบของฉัน Arduino SE คำถาม 34189 , วิธีการเพิ่มชีวิตของ EEPROM? .)


2

ฉันใช้หมายเลขลำดับการหมุนสำหรับสิ่งนี้ (คล้ายกับคำตอบของปีเตอร์) หมายเลขลำดับสามารถน้อยได้เพียง 1 บิตหากจำนวนองค์ประกอบในคิวเป็นเลขคี่ ส่วนหัวและส่วนท้ายนั้นจะถูกทำเครื่องหมายด้วย 2's 1 หรือ 0 ต่อเนื่องกัน

ตัวอย่างเช่นหากต้องการหมุน 5 องค์ประกอบหมายเลขลำดับจะเป็น:

{01010} (เขียนถึง 0) {11010} (เขียนถึง 1) {10010} (เขียนถึง 2) {10110} (เขียนถึง 3) {10100} (เขียนถึง 4) {10101} (เขียนถึง 5)


1

มีสองตัวเลือกขึ้นอยู่กับชนิดของ EEPROM ที่คุณมีและขนาดของข้อมูล

  1. หาก EEPROM ของคุณมีหน้าที่ลบได้แบบเอกเทศและคุณใช้ 1 หน้า (หรือมากกว่า) ให้ลบหน้าทั้งหมดยกเว้นหน้าที่ใช้งานอยู่และนำหน้ากลับมาใช้ใหม่ในลักษณะวน

  2. หากคุณใช้เศษส่วนของหน้าซึ่งจะต้องลบในครั้งเดียวพาร์ทิชันหน้านั้นลงในรายการข้อมูล ใช้รายการที่สะอาดทุกครั้งที่คุณเขียนและลบเมื่อคุณหมดรายการที่สะอาด

ใช้บิต "สกปรก" เพื่อบอกระหว่างรายการที่สะอาดและสกปรกหากจำเป็น (โดยปกติคุณมีอย่างน้อยหนึ่งไบต์ซึ่งรับประกันว่าแตกต่างจาก 0xFF ซึ่งสามารถใช้เพื่อติดตามรายการที่สกปรก)

หากไลบรารี EEPROM ของคุณไม่แสดงฟังก์ชั่นลบ (เช่น Arduino) นี่เป็นเคล็ดลับที่เรียบร้อยสำหรับอัลกอริทึม # 2: เนื่องจากรายการ EEPROM แรกของคุณถูกนำมาใช้เสมอคุณสามารถกำหนดค่าบิต "สกปรก" ได้โดยการอ่าน จากนั้นเมื่อคุณหมดรายการที่สะอาดแล้วคุณเพียงแค่เริ่มต้นอีกครั้งจากรายการแรกการย้อนกลับบิต "สกปรก" และรายการที่เหลือของคุณจะถูกทำเครื่องหมายเป็น "สะอาด" โดยอัตโนมัติ

หมายเลขลำดับและแคตตาล็อกเป็นการสิ้นเปลืองพื้นที่เว้นแต่คุณต้องการติดตามหน้าไม่ดีหรืออัปเดตส่วนต่าง ๆ ของข้อมูล EEPROM ของคุณอย่างอิสระ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.