Phương pháp hoặc chức năng để xác định xem con trỏ là địa chỉ trong flash hoặc RAM?


7

Tôi đang làm việc với một vi điều khiển ARM Cortex M4 có DMA hoặc bộ điều khiển DMA ngoại vi. Một yêu cầu của DMA là nó không thể truy cập các con trỏ tới các địa chỉ tồn tại trong flash mà chỉ có các con trỏ tới các địa chỉ trong RAM. Có cách nào để xác định xem một con trỏ cụ thể trỏ đến flash hoặc RAM không?

Nếu không, tôi nghĩ rằng tôi thực sự cần phải khởi tạo bộ đệm trong RAM sau đó strcpy hoặc một cái gì đó tương tự để chuyển những gì có trong flash vào RAM để DMA có thể đọc nó. Có ai biết một cách tốt hơn để làm điều này để không lãng phí thời gian của CPU nếu không có cách nào để biết nếu con trỏ trỏ đến flash hoặc RAM?

Đây là trên một SAM4S Atmel.


1
Nó có phải được xác định trong thời gian chạy không? Có phải chúng ta đang nói C ở đây?
Eugene Sh.

Vâng, vì vậy macro là ra khỏi câu hỏi tôi đoán. Chỉnh sửa ngay.
Pugz

Bạn có thể chia sẻ MCU nào có yêu cầu này? Đây có thể là một câu hỏi hữu ích + câu trả lời cho những người khác là tốt.
corecode

Đây là một SAM4S Atmel. Tôi sẽ chỉnh sửa câu hỏi.
Pugz

Câu trả lời:


5

Bạn biết bản đồ bộ nhớ của vi điều khiển của mình, vì vậy bạn chỉ cần kiểm tra con trỏ của mình dựa vào địa chỉ RAM bắt đầu và kết thúc. Trong hầu hết các trường hợp, bản liên kết của bạn sẽ cung cấp các địa chỉ này, vì vậy bạn không cần phải tự nhập chúng (chi tiết sẽ phụ thuộc vào bản liên kết của bạn). Lưu ý rằng khi bạn sử dụng trình liên kết, các giá trị sẽ không được biết tại thời điểm biên dịch, vì vậy trình biên dịch không thể tối ưu hóa các so sánh so với các con trỏ biết.


5

Vấn đề chính với việc kiểm tra xem một con trỏ có nằm trong phạm vi cụ thể không may là chính tiêu chuẩn C. Con trỏ số học có một hành vi được xác định duy nhất nếu thực hiện trên con trỏ cùng loại trong phạm vi bộ nhớ của cùng một đối tượng (ví dụ trong cùng một phạm vi mảng phân bổ). Một toán tử so sánh được định nghĩa là các phép toán số học, hạn chế này cũng áp dụng cho chúng. Một cách giải quyết cho vấn đề này sẽ là chuyển các con trỏ tới uintptr_tkiểu được xác định trong stdint.h, đây là một kiểu số nguyên được đảm bảo để giữ một giá trị con trỏ. Và sau đó thực hiện so sánh của bạn.

Bây giờ đến phần để có được ranh giới đúng. Thông thường, một dự án C sẽ chứa một số loại tập lệnh liên kết xác định vùng nhớ của kiến ​​trúc cụ thể. Thông thường, nó sẽ bao gồm các dòng tương tự như sau:

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x40000
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000
}

sau đó, trong cùng một kịch bản, các định nghĩa sau có thể được thêm vào:

  _flash_start = ORIGIN(FLASH);
  _flash_end = ORIGIN(FLASH) + LENGTH(FLASH);

Và sau đó trong mã C, các ký hiệu này có thể được truy cập bằng cách sử dụng:

extern int _flash_start ;  
extern int _flash_end;

Và sau đó là một phần khó khăn: Địa chỉ của _flash_startsẽ tương ứng với địa chỉ bắt đầu flash và địa chỉ của _flash_endsẽ tương ứng với địa chỉ kết thúc flash. Tức là &_flash_start&_flash_endđang cung cấp cho bạn phạm vi mong muốn.


5

Nếu MCU của bạn tuân theo các quy ước ARM Cortex, bạn có thể xem xét mức độ nhanh nhất của địa chỉ được đề cập:

int
inflash_p(void *addr)
{
    uintptr_t addr_int = addr;
    unsigned int addrtype = addr_int >> 28;

    // 0 = flash, 1,2 = ram, 4 = periph, e = system
    return (addrtype == 0);
}

Cảm ơn, tôi đã không nhận ra điều đó! Nguồn gốc của cái này là gì, TRM?
Domen

Xin lỗi, tôi không nhớ vào lúc này. Khi tôi gặp lại nó, tôi sẽ chỉnh sửa câu trả lời.
corecode

1 + 2 - ý của bạn là gì? Bạn có nghĩa là trả về 1 hoặc 2 có nghĩa là trong RAM, hoặc 3 có nghĩa là trong RAM?
Pugz

Tôi nghĩ nó có nghĩa 0x10000000- 0x2fffffffhay nói cách khác, mọi địa chỉ bắt đầu bằng nibble 1hoặc 2.
Domen

2

Bạn có thể truyền con trỏ tới một số nguyên, sau đó so sánh giá trị của nó với không gian địa chỉ flash như được xác định trong bản đồ bộ nhớ của MCU. Ví dụ: nếu bộ nhớ flash của bạn ở địa chỉ 0x10000000 - 0x1001ffff, bạn có thể làm:

void DMA_Function(uint8_t *ptr)
{
    uint32_t ptrAddress = (uint32_t)ptr;

    if (ptrAddress >= 0x10000000 && ptrAddress < 0x10020000)
        //The address is in flash
    else
        //The address is not in flash

    ...
}

Tất nhiên, trong mã thực tế, tốt hơn là sử dụng các hằng số thay vì các địa chỉ được mã hóa cứng - chẳng hạn như FLASH_START_ADDR và ​​FLASH_END_ADDR. Nếu bạn muốn linh hoạt hơn, bạn có thể xác định các biến liên kết cho các địa chỉ flash, điều này sẽ giữ các địa chỉ bên ngoài mã nguồn của bạn hoàn toàn.

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.