Chương trình EEPROM AVR trực tiếp từ nguồn C


11

Khi bạn bao gồm mã sau đây trong nguồn AVR C, rõ ràng bạn có thể lập trình trực tiếp các cầu chì mà không cần thêm lệnh hoặc tệp .hex:

#include <avr/io.h>

FUSES = {
        .low =          LFUSE_DEFAULT ,
        .high =         HFUSE_DEFAULT ,
        .extended =     EFUSE_DEFAULT ,
};

Có một mẹo tương tự với các giá trị chương trình trong EEPROM không?

Tôi đã kiểm tra /usr/lib/avr/include/avr/fuse.hnơi tôi có thể tìm thấy một số nhận xét về một macro, nhưng tôi không thể tìm thấy một nhận xét tương tự trong /usr/lib/avr/include/avr/eeprom.hvà diễn giải các công cụ tiền xử lý là một chút ra khỏi liên minh của tôi.

Sẽ thực sự tiện dụng nếu tôi có thể bao gồm các giá trị EEPROM mặc định trong mã nguồn C. Bất cứ ai biết làm thế nào để thực hiện điều đó?

chỉnh sửa1:

Thủ thuật FUSES này chỉ được thực hiện tại ISP-time chứ không phải RUN-time. Vì vậy, không có cầu chì nào được lập trình trong mã lắp ráp kết quả trong bộ điều khiển. Thay vào đó, lập trình viên sẽ tự động quay vòng qua một chu trình lập trình FUSES bổ sung.

chỉnh sửa2:

Tôi sử dụng chuỗi công cụ avr-gcc và avrdude trên Linux.


Đây chỉ là khi lập trình ISP? Hầu hết các bộ tải khởi động không cho phép bạn lập trình cầu chì, phải không?
angelatlarge

2
Tôi không có thời gian để viết một câu trả lời đầy đủ vào lúc này, nhưng như một gợi ý hãy thử tìm kiếm trên chỉ thị EEMEM. Ngoài ra, bạn có thể cần thay đổi cài đặt trình liên kết để tạo tệp .EPP riêng biệt mà lập trình viên sẽ sử dụng.
PeterJ

@angelatlarge Chỉ lập trình ISP. Không có bootloader trong thiết lập này.
jippie

2
Lưu ý rằng câu trả lời cho điều này phụ thuộc hoàn toàn vào những gì mà toolchain sẵn sàng ghi lại trong đầu ra của nó và những gì lập trình viên sẵn sàng phân tích. Hầu hết các bộ công cụ có thể được cấu hình để tạo một phần đặc biệt (hoặc đặt dữ liệu tại một địa chỉ hư cấu) để cuối cùng, nó sẽ được lập trình viên có thể trích xuất nó hoặc có thể được điều khiển bởi một tập lệnh tùy chỉnh sẽ làm như vậy.
Chris Stratton

Câu trả lời:


7

Với avr-gcc, EEMEMmacro có thể được sử dụng cho định nghĩa của biến, xem libctài liệu và ví dụ ở đây :

#include <avr/eeprom.h>
char myEepromString[] EEMEM = "Hello World!";

tuyên bố mảng các ký tự nằm trong một phần có tên ".eeprom" mà sau khi biên dịch cho lập trình viên biết rằng dữ liệu này sẽ được lập trình cho EEPROM. Tùy thuộc vào phần mềm lập trình của bạn, bạn có thể cần phải cung cấp rõ ràng tên của ".eep" -file được tạo trong quá trình xây dựng cho lập trình viên, hoặc nó có thể tự tìm thấy nó.


Tôi đã sử dụng một tên tệp hơi khác so với 'tôi', nhưng đây là những lệnh tôi đưa vào để lập trình EEPROM từ dòng lệnh (và makefile):
jippie

1
Tạo một tệp chứa dữ liệu Intel Hex được lập trình viên sử dụng:avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 ihex $(src).elf $(src).eeprom.hex
jippie

1
Việc lập trình thực tế được thực hiện bởi:avrdude -p$(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) -v -U eeprom:w:$(src).eeprom.hex
jippie 30/03/13

7

Có, bạn có thể tự ghi dữ liệu mặc định vào EEPROM trong mã nguồn. Trước tiên, hãy xem hướng dẫn tuyệt vời này trên EEPROM với AVR: Hướng dẫn về EEPROM của Dean. Ngoài ra, tôi nên thêm rằng nên tạo một tệp .eep chứa dữ liệu EEPROM bằng cách sử dụng tệp tạo tệp sẽ được lập trình cho thiết bị cùng với mã nguồn. Tuy nhiên, nếu bạn không quen với các hoạt động makefile và linker khác nhau, nó vẫn có thể được thực hiện từ trong tệp mã nguồn của bạn - nó sẽ xảy ra ngay khi mạch được cấp nguồn, làm trì hoãn hoạt động của chương trình ban đầu.

Khi bắt đầu chương trình (trước bất kỳ loại vòng lặp chính nào), bạn có thể làm một cái gì đó như thế này:

#include <avr/eeprom.h>

#define ADDRESS_1 46  // This could be anything from 0 to the highest EEPROM address
#define ADDRESS_2 52  // This could be anything from 0 to the highest EEPROM address
#define ADDRESS_3 68  // This could be anything from 0 to the highest EEPROM address

uint8_t dataByte1 = 0x7F;  // Data for address 1
uint8_t dataByte2 = 0x33;  // Data for address 2
uint8_t dataByte3 = 0xCE;  // Data for address 3

eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
eeprom_update_byte((uint8_t*)ADDRESS_2, dataByte2);
eeprom_update_byte((uint8_t*)ADDRESS_3, dataByte3);

Chức năng "cập nhật" trước tiên sẽ kiểm tra xem giá trị đó đã có chưa, để tiết kiệm cho việc ghi không cần thiết, duy trì tuổi thọ EEPROM. Tuy nhiên, làm điều này cho rất nhiều vị trí có thể mất khá nhiều thời gian. Có thể tốt hơn để kiểm tra một vị trí duy nhất. Nếu đó là giá trị mong muốn, thì phần còn lại của các bản cập nhật có thể được bỏ qua hoàn toàn. Ví dụ:

if(eeprom_read_byte((uint8_t*)SOME_LOCATION) != DESIRED_VALUE){
  eeprom_write_byte((uint8_t*)SOME_LOCATION, DESIRED_VALUE);
  eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
  eeprom_update_byte((uint8_t*)ADDRESS_2, dataByte2);
  eeprom_update_byte((uint8_t*)ADDRESS_3, dataByte3);
}

Nếu bạn đang tìm cách cập nhật lượng lớn dữ liệu, hãy thử sử dụng các chức năng khác như eeprom_update_block(...). Và chắc chắn đọc hướng dẫn đó; nó được viết tốt

Bạn có thể đặt tất cả các câu lệnh cập nhật EEPROM trong một câu lệnh điều kiện tiền xử lý. Điều này rất đơn giản để làm:

#if defined _UPDATE_EEPROM_
  #define ADDRESS_1 46  // This could be anything from 0 to the highest EEPROM address
  uint8_t dataByte = 0x7F;  // Data for address 1
  eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
#endif // _UPDATE_EEPROM_

Bit mã này thậm chí sẽ không được biên dịch trừ khi bạn làm như sau:

#define _UPDATE_EEPROM_

Bạn có thể để nó ở đây dưới dạng một nhận xét, sau đó bỏ ghi chú nếu bạn cần thay đổi các giá trị EEPROM mặc định. Để biết thêm thông tin về bộ tiền xử lý C, hãy xem hướng dẫn trực tuyến này . Tôi nghĩ rằng bạn có thể quan tâm nhất trong các phần về macro và báo cáo điều kiện.


Có vẻ như câu trả lời đúng nằm trong đoạn cuối của tệp PDF được liên kết. Ch. 7 Setting Initial Values.
jippie

Ư, bạn đung. Tôi đã đề cập đến điều đó trong đoạn đầu tiên của mình, nhưng tiếp tục trong trường hợp bạn không quen thuộc với các tệp .eep và trình liên kết trong tệp thực hiện!
Kurt E. Clothier 27/03/13

1
Sử dụng địa chỉ EEPROM tĩnh là thực hành xấu. Thay vào đó, tốt hơn là sử dụng thuộc tính EEMEM và để trình biên dịch quản lý phân phối địa chỉ. Ngoài ra, tôi khuyên bạn nên thực hiện / thực hiện kiểm tra CRC qua từng phần. Nếu CRC thất bại, phần tương ứng chứa dữ liệu chưa được khởi tạo hoặc bị hỏng. Bằng cách này, bạn thậm chí có thể thực hiện cơ chế dự phòng cho cấu hình trước đó trong trường hợp hỏng dữ liệu.
Rev1.0

"Sử dụng địa chỉ EEPROM tĩnh là thực tế xấu." Tại sao?
angelatlarge

1
Khi sử dụng EEMEMcác biến, trình biên dịch sẽ đảm nhiệm việc quản lý biến nào nằm trong EEPROM. Bằng cách này, bạn chỉ hoạt động trên các con trỏ (không đổi, do trình biên dịch tạo) cho các biến khi truy cập dữ liệu. Mặt khác, nếu bạn xác định rõ ràng địa chỉ nơi mỗi biến cư trú, bạn sẽ phải tự chăm sóc các địa chỉ đó, bao gồm đảm bảo rằng không có biến nào vô tình chiếm cùng một địa chỉ, ghi đè lên nhau; hoặc tính lại tất cả các địa chỉ trong trường hợp kích thước lưu trữ của một biến thay đổi trong tương lai, v.v.
JimmyB
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.