2010-06-15 26 views
7

Tôi đang cố thực hiện một hàm từ RAM trên bộ xử lý Cortex-M3 (STM32). Chức năng này sẽ xóa và ghi lại đèn flash bên trong, vì vậy tôi chắc chắn cần phải có trong RAM nhưng làm cách nào để làm điều đó?Làm cách nào để thực hiện một hàm từ RAM trên Cortex-M3 (STM32)?

Điều tôi đã thử là: Sao chép hàm vào mảng byte trong RAM bằng memcpy (kiểm tra xem nó có được căn chỉnh chính xác không), thiết lập con trỏ hàm để trỏ tới mảng byte, sau đó gọi hàm (con trỏ) .

Điều này làm việc tốt cho 10 hướng dẫn (tôi có thể thực hiện theo trình gỡ rối) nhưng sau đó tôi gặp lỗi buss và bộ xử lý đặt lại. Lỗi buss xảy ra trên lần thứ hai đi qua một vòng lặp để mã nên được sử dụng tốt (vì nó hoạt động pass đầu tiên). Tôi nghĩ rằng việc truy cập RAM nhanh hơn sẽ tăng thời gian buss theo một cách nào đó ...

Dù sao có cách nào đúng để thực hiện việc này? Làm thế nào một tập tin phân tán trông giống như đặt một chức năng trong RAM tự động (Tôi đang sử dụng Keil uVision cho Cortex-M3)?

Edit: Thông tin thêm: toolchain: RealView MDK-ARM V 4.10 Compiler: Armcc v4.0.0.728 Assembler: Armasm v4.0.0.728 Linker: ArmLink v4.0.0.728 Processor: STM32F103ZE

Bit IMPRECISERR được đặt trong thanh ghi lỗi khi lỗi xảy ra.

+0

Ummm Tôi nghĩ bạn nên đăng nhiều hơn hoặc ít hơn vào diễn đàn của nhà sản xuất vì bạn đang sử dụng phần cứng cụ thể, bạn có thể cung cấp thêm chi tiết, bạn đang sử dụng trình biên dịch nào, bạn đang gỡ lỗi như thế nào, bất kỳ mẫu mã nào * một * người có kiến ​​thức có thể trả lời câu hỏi này, khác hơn thế ... – t0mm13b

+1

@ tommieb75: Nhưng tôi thích các bạn nhiều hơn thế! – c0m4

Trả lời

7

Sự cố khi lặp vòng lặp có thể do hàm đang phân nhánh thành một địa chỉ tuyệt đối và không liên quan đến vị trí hàm mới trong RAM. Sẽ truy cập vào vị trí mã ban đầu tại thời điểm đó gây ra một lỗi xe buýt vì hoạt động xóa flash?

Tôi tin rằng bạn có thể đánh dấu một hàm được biên dịch và sao chép vào RAM một cách chính xác bằng CARM bằng cách thêm chỉ thị __ram vào định nghĩa hàm. Đối với hướng dẫn về cách làm tương tự với trình biên dịch RealView xem bài viết EXECUTING FUNCTIONS IN RAM hỗ trợ kỹ thuật:

μVision cho phép bạn xác định vị trí các module đến các vùng bộ nhớ cụ thể là nhập vào hộp thoại Dự án - Options - Target. Để làm như vậy, hãy nhấp chuột phải vào trên tệp nguồn (hoặc nhóm tệp) và mở hộp thoại Tùy chọn - Thuộc tính. Sau đó, chọn bộ nhớ vùng dưới Phân bổ bộ nhớ.

Có một ví dụ trong thư mục ARMExamplesRAM_Function.

Điều đó sẽ tạo mã khởi động để chăm sóc sao chép chức năng sang RAM và liên kết cuộc gọi đến vị trí đó một cách chính xác.Nếu không, nếu bạn cần tự động sao chép các hàm tùy ý vào RAM, hãy xem xét biên dịch position independent code (PIC) bằng RealView.

+0

Câu trả lời hay! – c0m4

+0

Tôi đã có cùng một vấn đề ngoại trừ tôi không sử dụng RTX hoặc bất kỳ thư viện vì vậy tôi không bao gồm mã của trình biên dịch tự động tải các chức năng RAM vào RAM. Tôi muốn có vùng tải hoặc vùng thực thi trong RAM, nơi mã của tôi thực sự sẽ được liên kết nhưng tôi cần trình lập trình JTAG để tải mã vào địa chỉ khác (trong flash). Lý tưởng nhất là trong tệp .sct (Tôi đang sử dụng Keil MDK) Tôi muốn có một phần nơi tôi chỉ định địa chỉ lưu trữ và liên kết. Nhưng tôi chưa biết cách thực hiện điều đó. –

+0

@Captain: Bạn có thể cân nhắc việc mở một câu hỏi mới với thông tin cụ thể của bạn. Tuy nhiên, tôi tin rằng giải pháp trên cũng được áp dụng trong trường hợp của bạn. –

2

Nếu không biết thêm về tình huống của bạn, tôi chỉ có thể đề xuất một vài điều chung ... đảm bảo bạn có ngăn xếp hợp lệ cho chức năng đó (hoặc tránh tất cả các hoạt động ngăn xếp trong chức năng), ngắt của bạn bị vô hiệu hóa và bất kỳ vectơ nào trong bảng vectơ hệ thống không trỏ tới mã sẽ biến mất khi bạn xóa flash. Cuối cùng, hãy đảm bảo chức năng của bạn là được liên kết để chạy tại địa chỉ bạn đã đặt ... mã có thể không thể định vị lại và có thể chuyển đến vị trí cũ là vị trí cũ.

1

Với trình biên dịch IAR (Tôi biết câu hỏi của bạn là về Keil nhưng tôi không có nó để chơi với), bạn có thể đánh dấu toàn bộ dự án hoặc một tệp riêng lẻ là "vị trí độc lập". Từ việc sử dụng điều này trong quá khứ với các bộ vi xử lý khác, nó có nghĩa là bạn có thể di chuyển nó "bất cứ nơi nào" và nó vẫn hoạt động ok

2

Vì ARM có khả năng hạn chế tải dữ liệu ngay lập tức, các tiện ích tạo mã cho mã thường xuyên ARM và dữ liệu. Ví dụ, một tuyên bố như

void myRoutine(void) 
{ 
    myVar1=0x12345678; 
    myVar2=0x87654321; 
} 

có thể kết thúc như một cái gì đó như:

myRoutine:   
    ldr r0,=myVar1; Load the address of _myVar 
    ldr r1,=0x12345678 
    str r1,[r0] 
    ldr r0,=myVar1; Load the address of _myVar 
    ldr r1,=0x87654321 
    str r1,[r0] 
    bx lr 

which would get translated into: 
    ldr r0,dat1 
    ldr r1,dat2 
    str r1,[r0] 
    ldr r0,dat3 
    ldr r1,dat4 
    str r1,[r0] 
    bx lr 
... followed some time later by 
dat1 dcd _myVar1 
dat2 dcd 0x12345678 
dat3 dcd _myVar2 
dat4 dcd 0x12345678 

or perhaps even something like: 
    mar r0,dat1 
    ldrm r0,[r1,r2,r3,r4] 
    str r2,[r1] 
    str r4,[r3] 
    bx lr 
... followed some time later by 
dat1 dcd _myVar1 
dat2 dcd 0x12345678 
dat3 dcd _myVar2 
dat4 dcd 0x12345678 

Lưu ý rằng _myVar và 0x12345678 có thể được đặt ngay sau khi mã cho thói quen mà chúng xuất hiện; nếu bạn cố gắng xác định độ dài của quy trình sử dụng nhãn theo hướng dẫn cuối cùng, độ dài đó sẽ không bao gồm dữ liệu bổ sung.

Một điều bổ sung cần lưu ý với ARM là vì lý do lịch sử, địa chỉ mã thường sẽ có ít bit quan trọng nhất mặc dù mã thực sự bắt đầu trên ranh giới nửa từ. Do đó, một hướng dẫn có địa chỉ là 0x12345679 sẽ chiếm hai hoặc bốn byte bắt đầu từ 0x12345678. Điều này có thể phức tạp tính toán địa chỉ cho những thứ như memcpy.

Đề xuất của tôi là viết một thói quen nhỏ trong ngôn ngữ lắp ráp để thực hiện những gì bạn cần. Nó chỉ là một vài hướng dẫn, bạn có thể biết chính xác mã đang làm gì và phụ thuộc vào địa chỉ nào và bạn sẽ không phải lo lắng về các phiên bản trình biên dịch trong tương lai thay đổi mã của bạn theo cách như vậy để phá vỡ một cái gì đó [ví dụ: phiên bản thứ ba của mã trên sẽ không có vấn đề gì ngay cả khi dat1 hạ cánh trên ranh giới halfword lẻ vì lệnh LDR của M3 có thể xử lý các lần đọc chưa được ký, nhưng phiên bản thứ tư (nhanh hơn và nhỏ gọn hơn) bằng LDRM sẽ bị lỗi trong trường hợp này; ngay cả khi phiên bản hiện tại của trình biên dịch sử dụng bốn lệnh LDR, một phiên bản trong tương lai có thể sử dụng LDRM].

Các vấn đề liên quan