Mục lục:

Phần 1 Lắp ráp ARM TI RSLK Giáo trình học Robot Phòng thí nghiệm 7 STM32 Nucleo: 16 bước
Phần 1 Lắp ráp ARM TI RSLK Giáo trình học Robot Phòng thí nghiệm 7 STM32 Nucleo: 16 bước

Video: Phần 1 Lắp ráp ARM TI RSLK Giáo trình học Robot Phòng thí nghiệm 7 STM32 Nucleo: 16 bước

Video: Phần 1 Lắp ráp ARM TI RSLK Giáo trình học Robot Phòng thí nghiệm 7 STM32 Nucleo: 16 bước
Video: [Lập trình hướng sự kiện cho vi điều khiển] Bài 2: Làm việc với mStack Console 2024, Tháng bảy
Anonim
Image
Image

Trọng tâm của Có thể hướng dẫn này là bộ điều khiển vi mô STM32 Nucleo. Động lực cho việc này để có thể tạo ra một dự án lắp ráp từ những bộ xương trần. Điều này sẽ giúp chúng tôi nghiên cứu sâu hơn và hiểu dự án MSP432 Launchpad (TI-RSLK) đã từng là chủ đề của một số Sách hướng dẫn.

Không có nhiều trợ giúp trực tuyến để tạo một dự án chỉ lắp ráp cho MSP432, bằng cách sử dụng Code Composer Studio. Cho đến nay, chúng tôi chỉ sao chép / dán từ một dự án lắp ráp đã có từ trước. Cách tiếp cận này đã phục vụ chúng tôi tốt.

Tuy nhiên, hiện tại, đối với Lab 7, chúng tôi đã gặp một chút vấn đề. Hoặc ít nhất là một cơn nấc cụt tạm thời. Lab 7 giới thiệu máy trạng thái hữu hạn và điều đầu tiên chúng ta gặp phải là nhu cầu tạo và sử dụng một mảng giá trị. Vì khóa học TI chủ yếu sử dụng lập trình C - đây không phải là vấn đề. Nhưng những Hướng dẫn này đã tập trung vào lắp ráp, không phải C.

Hơn nữa, vì mảng là các giá trị chỉ đọc, sẽ tốt hơn nếu đặt nó vào bộ nhớ flash, không phải RAM.

Có vẻ như có rất nhiều trợ giúp trực tuyến cho các dự án lắp ráp sử dụng MCU STM32, do đó, chúng tôi bắt đầu với Có thể hướng dẫn này, với mục tiêu sử dụng những gì đã học, sau đó áp dụng cho MSP432 và Code Composer Studio.

Trên con đường đạt được mục tiêu đó, chúng tôi cũng sẽ có kinh nghiệm với một bộ điều khiển vi mô phổ biến khác.

Bước 1: Kiểm tra thiết bị ban đầu

Thử nghiệm ban đầu của thiết bị
Thử nghiệm ban đầu của thiết bị
Thử nghiệm ban đầu của thiết bị
Thử nghiệm ban đầu của thiết bị
Thử nghiệm ban đầu của thiết bị
Thử nghiệm ban đầu của thiết bị

Một lần nữa, tại sao lại chọn STM32 Nucleo nói riêng?

Thành thật? Bởi vì tôi đang tìm kiếm các bài viết hay về các dự án lắp ráp kim loại trần cho bộ điều khiển ARM, và tôi đã xem qua loạt bài này. Và cũng bởi vì STM32 dường như là một MCU phổ biến.

Tôi đã thực hiện một số nghiên cứu (có rất nhiều phiên bản để lựa chọn - xem hình trên), nhưng cuối cùng nó đã trở thành những gì tôi thực sự có thể nhận được, vì tôi sẽ sử dụng Amazon (ở Hoa Kỳ).

Nó đi kèm trong một gói đơn giản nhưng chuyên nghiệp, với một số hướng dẫn khởi động. Có một chút buồn cười khi thấy rằng bản demo được ghi vào bộ điều khiển gần như chính xác như những gì chúng tôi đã làm trong các Huấn luyện viên trước đây - một đèn LED nhấp nháy và thay đổi tốc độ chỉ sau một lần nhấn nút.

Có vẻ như bảng phát triển này rất giống với MSP432 ở chỗ có 2 đèn LED và một nút người dùng. MSP432 có 2 nút người dùng.

Như bạn có thể thấy trong các bức ảnh, tôi hơi ngạc nhiên khi thấy bo mạch này có một mini chứ không phải micro USB. Đã phải chạy ra ngoài để mua một sợi dây.

Một thử nghiệm tốt khác là khi bạn kết nối nó với máy tính của mình (tôi đang sử dụng hộp Linux), nó sẽ hiển thị trong trình quản lý tệp của tôi, dưới dạng hệ thống tệp, được gọi là "NODE_F303RE". Mở ra sẽ hiển thị hai tệp, một HTML và một văn bản.

Chỉ vậy thôi, nhưng ít nhất nó cũng cho biết khả năng kết nối có vẻ khá dễ dàng.

Bây giờ chúng tôi đã sẵn sàng để bắt đầu.

Tôi sẽ cố gắng không lặp lại bất kỳ thông tin tốt nào từ loạt bài viết về IVONOMICON Bare Metal, mà là tăng cường nó.

Bước 2: Những điều cần thiết

Điều đầu tiên chúng ta cần là một trình biên dịch.

Và sau đó, chúng tôi cần một trình gỡ lỗi:

devchu @ chubox: ~ $ sudo apt-get install gdb-arm-none-eabi Đọc danh sách gói… Xong Xây dựng cây phụ thuộc Đọc thông tin trạng thái… Xong Các gói MỚI sau sẽ được cài đặt: gdb-arm-none-eabi 0 được nâng cấp, 1 mới đã cài đặt, 0 để loại bỏ và 8 không được nâng cấp. Cần lấy 2, 722 kB tài liệu lưu trữ. Sau thao tác này, 7, 738 kB dung lượng ổ đĩa bổ sung sẽ được sử dụng. Nhận: 1 https://us.archive.ubuntu.com/ubuntu xenial / vũ trụ amd64 gdb-arm-none-eabi amd64 7.10-1ubuntu3 + 9 [2, 722 kB] Tìm nạp 2, 722 kB trong 1 giây (1, 988 kB / s) Đang chọn gói không được chọn trước đó gdb-arm-none-eabi. (Đang đọc cơ sở dữ liệu… 262428 tệp và thư mục hiện được cài đặt.) Đang chuẩn bị giải nén… / gdb-arm-none-eabi_7.10-1ubuntu3 + 9_amd64.deb… Đang giải nén gdb-arm-none-eabi (7.10-1ubuntu3 + 9)… Đang xử lý kích hoạt cho man-db (2.7.5-1)… Thiết lập gdb-arm-none-eabi (7.10-1ubuntu3 + 9)…

Bước 3: Những điều cần thiết - Windows

Bước trên giả sử chúng ta đang sử dụng Linux. Điều gì sẽ xảy ra nếu chúng ta đang sử dụng Windows?

Bạn có thể truy cập trang web arm Developer và có một số tùy chọn tải xuống. Tôi đang sử dụng máy tính Windows 8.

Trong quá trình cài đặt, tôi đã chọn cài đặt nó vào ổ "C: \" gốc thay vì Program Files chỉ vì tôi cũng đang sử dụng cygwin và việc tạo liên kết từ thùng rác cục bộ của tôi đến thư mục C: / root dễ dàng hơn tất cả lộn xộn trong đường dẫn đến Tệp chương trình (có khoảng trắng, v.v.).

Do đó, môi trường và đường dẫn cygwin của tôi, v.v., trông giống như sau:

C: / cygwin64 / home / bin / arm-none-eabi-gcc, trong đó arm-none-eabi-gcc là một liên kết đến C: / GNUToolsArmEmbedded / 7.2018.q2.update / bin / arm-none-eabi- gcc.

Sau đó, tôi tạo một thư mục "dev" trong cygwin home, và đó là nơi tôi đặt tệp core. S và chạy lệnh biên dịch. (xem thêm bên dưới để biết nội dung của trình biên dịch).

Tôi đã làm điều tương tự cho gdb (arm-none-eabi-gdb).

Bước 4: Những điều cần thiết là gì

Vậy "gcc-arm-none-eabi" là gì?

Trình biên dịch gnu (GCC) sẽ biên dịch các ngôn ngữ lập trình (như C) thành mã gốc cho máy mà nó đang chạy. Ví dụ: nếu bạn định biên dịch một số mã C bằng GCC trên máy Windows của mình, nó sẽ được xây dựng để chạy trên máy Windows. Tệp thực thi được tạo sẽ không (thường) chạy trên vi điều khiển ARM.

Vì vậy, để xây dựng các chương trình được tải xuống và ghi vào bộ vi điều khiển ARM (trong trường hợp hiện tại của chúng ta là STM32 Nucelo), chúng ta cần cung cấp cho GCC một thứ khác: khả năng "biên dịch chéo". Đó là, khả năng tạo tệp thực thi, không phải cho hệ thống gốc (và bộ xử lý) của nó, mà cho hệ thống đích (bộ điều khiển vi ARM). Đó là lúc "gcc-arm-none-eabi" phát huy tác dụng.

Vậy "gdb-arm-none-eabi" là gì?

Khi chúng tôi đã tải xuống và ghi (flash) tệp thực thi mới được tạo vào bộ điều khiển vi mô, chúng tôi có thể muốn gỡ lỗi nó - từng dòng một của mã. GDB là trình gỡ lỗi gnu và nó cũng cần một cách để thực hiện công việc của mình, nhưng nhắm mục tiêu đến một hệ thống khác.

Do đó, gdb-arm-none-eabi là của GDB, gcc-arm-none-eabi là GCC.

Một gói cài đặt được đề xuất khác là "libnewlib-arm-none-eabi". Đó là cái gì?

Newlib là một thư viện C và thư viện toán học được thiết kế để sử dụng trên các hệ thống nhúng. Nó là một tập hợp của một số bộ phận thư viện, tất cả đều có giấy phép phần mềm miễn phí giúp chúng dễ dàng sử dụng trên các sản phẩm nhúng.

Và cuối cùng là gói "libstdc ++ - arm-none-eabi". Đó là một điều khá rõ ràng; đó là thư viện C ++ cho trình biên dịch chéo; cho bộ điều khiển vi mô ARM nhúng.

Bước 5: Tệp liên kết

Tệp trình liên kết
Tệp trình liên kết
Tệp trình liên kết
Tệp trình liên kết

Hãy tạo một tập lệnh trình liên kết.

Một phần hoặc khối quan trọng trong tệp này sẽ là lệnh MEMORY.

--- từ sourceware.org:

Cấu hình mặc định của trình liên kết cho phép phân bổ tất cả bộ nhớ có sẵn. Bạn có thể ghi đè điều này bằng cách sử dụng lệnh MEMORY. Lệnh MEMORY mô tả vị trí và kích thước của các khối bộ nhớ trong mục tiêu. Bạn có thể sử dụng nó để mô tả vùng nhớ nào có thể được trình liên kết sử dụng và vùng nhớ nào nó phải tránh. Sau đó, bạn có thể gán các phần cho các vùng bộ nhớ cụ thể. Trình liên kết sẽ đặt địa chỉ phần dựa trên các vùng bộ nhớ và sẽ cảnh báo về các vùng trở nên quá đầy. Trình liên kết sẽ không xáo trộn các phần xung quanh để phù hợp với các vùng có sẵn. Tập lệnh trình liên kết có thể chứa nhiều cách sử dụng lệnh MEMORY, tuy nhiên, tất cả các khối bộ nhớ được xác định sẽ được coi như thể chúng được chỉ định bên trong một lệnh MEMORY.:

KỈ NIỆM

{name [(attr)]: ORIGIN = origin, LENGTH = len…}

Ví dụ trong bài viết:

/ * Xác định điểm cuối của RAM và giới hạn của bộ nhớ ngăn xếp * // * (4KB SRAM trên dòng STM32F031x6, 4096 = 0x1000) * / / * (RAM bắt đầu ở địa chỉ 0x20000000) _estack = 0x20001000;

KỈ NIỆM

{FLASH (rx): ORIGIN = 0x08000000, LENGTH = 32K RAM (rxw): ORIGIN = 0x20000000, LENGTH = 4K}

Vì vậy, chúng ta cần tìm ra bao nhiêu FLASH (cho chương trình và hằng số của chúng ta, v.v.) và bao nhiêu RAM (để chương trình sử dụng; heap và stack, v.v.) cho bảng cụ thể của chúng ta. Điều này có một chút thú vị.

Chiếc thẻ nhỏ xinh đi kèm với Nucleo cho biết nó có bộ nhớ flash là 512 Kbyte và SRAM là 80 Kbyte. Tuy nhiên, khi kết nối nó với USB, nó được gắn kết như một hệ thống tệp với hai tệp và cả trình quản lý tệp và GParted đều cho biết nó có hơn 540 Kbyte dung lượng. (RAM?).

NHƯNG, cố gắng xóa hai tệp bằng trình quản lý tệp, ngắt kết nối rồi kết nối lại thiết bị, vẫn hiển thị hai tệp. (và trình quản lý tệp đã nhận ra điều gì đó vì có một biểu tượng "khóa" nhỏ trên mỗi tệp.

Vì vậy, chúng ta hãy đi với các số liệu trên thẻ. Vì vậy, bây giờ chúng tôi lấy ví dụ trên và chuyển đổi nó thành bảng cụ thể của chúng tôi.

Bạn có thể muốn sử dụng một cái gì đó giống như bộ chuyển đổi bộ nhớ trực tuyến này, để chuyển từ KB chung sang số byte cụ thể.

Sau đó, bạn có thể muốn sử dụng công cụ chuyển đổi từ thập phân sang hex trực tuyến.

/ * Xác định phần cuối của RAM và giới hạn của bộ nhớ ngăn xếp * /

/ * (4KB SRAM trên dòng STM32F031x6, 4096 = 0x1000) * // * ví dụ * /

/ * bước 1: (80KB SRAM trên STM32F303RE, 81920 = 0x14000) * // * bảng của chúng tôi * /

/ * bước 2, thêm kích thước hex vào địa chỉ bắt đầu hex (bên dưới). * /

/ * (RAM bắt đầu ở địa chỉ 0x20000000) * /

_estack = 0x20001000; / * ví dụ * /

_estack = 0x20014000; / * hội đồng quản trị của chúng tôi * /

KỈ NIỆM {

FLASH (rx): ORIGIN = 0x08000000, LENGTH = 512K

RAM (rxw): ORIGIN = 0x20000000, LENGTH = 80K

}

Hãy gọi tệp ở trên là "linker.script.ld".

Bước 6: Bảng vectơ

Bảng vectơ
Bảng vectơ

Bây giờ chúng ta sẽ tạo một tệp hợp ngữ nhỏ (với các lệnh) để thực hiện một số xử lý ngắt rất cơ bản. Chúng tôi sẽ làm theo ví dụ của bài viết và tạo tệp có tên "core. S".

Một lần nữa, đây là nội dung tệp ví dụ, nhưng tôi đã thực hiện một thay đổi cho bảng cụ thể của chúng tôi:

// Các hướng dẫn này xác định các thuộc tính của chip của chúng tôi và

// ngôn ngữ hợp ngữ mà chúng ta sẽ sử dụng:.syntax united / * Xem bên dưới sau vùng mã này * / /*.cpu cortex-m0 * / / * nhận xét dòng này của ví dụ * /.cpu cortex-m4 / * thay vào đó hãy thêm vỏ não của hội đồng quản trị của chúng tôi. xem hình trên trong bước này * / /*.fpu softvfp * / / * nhận xét dòng này của ví dụ * /.fpu vfpv4 / * thay vào đó là bảng của chúng tôi; nó có FPU * /.thumb // Vị trí bộ nhớ chung..global vtable.global reset_handler / * * Bảng vectơ thực tế. * Chỉ bao gồm kích thước của RAM và trình xử lý 'đặt lại' * để đơn giản hóa. * /.type vtable,% object vtable:.word _estack.word reset_handler.size vtable,.-vtable

Hmm.. Không chỉ thị '.align'

Tuy nhiên, đó không phải là điều quan trọng. Thêm về điều đó (có thể) sau.

.syntax thống nhất

.syntax [hợp nhất | chia]

Chỉ thị này thiết lập Cú pháp Tập lệnh như được mô tả trong phần ARM-Tập lệnh-Tập hợp

9.4.2.1 Cú pháp tập lệnh Hai cú pháp hơi khác nhau là hỗ trợ cho lệnh ARM và THUMB. Mặc định, được chia, sử dụng kiểu cũ trong đó các lệnh ARM và THUMB có cú pháp riêng, riêng biệt. Cú pháp mới, hợp nhất, có thể được chọn thông qua chỉ thị.syntax.

.fpu vfpv4

Trình biên dịch GCC có thể tạo ra các tệp nhị phân với một số tùy chọn liên quan đến dấu phẩy động: soft - phù hợp để chạy trên CPU không có FPU - các phép tính được thực hiện trong phần mềm bằng softfp do trình biên dịch tạo - phù hợp để chạy trên CPU có hoặc không có FPU - sẽ sử dụng FPU nếu có. Đối với trường hợp cụ thể của chúng tôi (bạn sẽ phải tự nghiên cứu), FPU của bảng cụ thể này tuân theo vfpv4. Bạn có thể phải chơi với cái này. Hoặc thậm chí để nó ở softfp.

.thumb (so với.arm)

Các vi điều khiển ARM này thực sự có sự kết hợp của các tập lệnh. Một là ARM, một là THUMB. Một sự khác biệt là hướng dẫn 16 bit so với hướng dẫn 32 bit. Do đó, lệnh này yêu cầu trình biên dịch coi các lệnh tiếp theo là THUMB hoặc ARM.

Chúng tôi sẽ chỉ lấy phần còn lại của tệp như hiện tại vì các Tài liệu hướng dẫn này chưa đi sâu vào lập trình hợp ngữ hướng ngắt.

Bước 7: Phiên bản lắp ráp của chương trình 'Hello World'

Phần sau cũng có thể đi vào tệp "core. S" đã được tạo trước đó. Điều này, một lần nữa, là từ ví dụ trong bài báo.

/ * * Trình xử lý Reset. Đã gọi khi đặt lại. * /.type reset_handler,% function reset_handler: // Đặt con trỏ ngăn xếp đến cuối ngăn xếp. // Giá trị '_estack' được xác định trong tập lệnh trình liên kết của chúng tôi. LDR r0, = _estack MOV sp, r0

// Đặt một số giá trị giả. Khi chúng ta thấy những giá trị này

// trong trình gỡ lỗi của chúng tôi, chúng tôi sẽ biết rằng chương trình của chúng tôi // được tải trên chip và đang hoạt động. LDR r7, = 0xDEADBEEF MOVS r0, # 0 main_loop: // Thêm 1 vào đăng ký 'r0'. ADDS r0, r0, # 1 // Lặp lại. B main_loop.size reset_handler,.-Reset_handler

Vì vậy, lực đẩy của chương trình trên là tải một mẫu dễ nhận biết vào một thanh ghi MCU lõi (trong trường hợp này là R7) và một giá trị tăng dần bắt đầu từ 0 vào một thanh ghi MCU lõi khác (trong trường hợp này là R0). Nếu chúng ta bước qua mã đang thực thi, chúng ta sẽ thấy dữ liệu của R0 tăng lên.

Nếu bạn đã theo dõi cùng với các Tài liệu hướng dẫn liên quan đến MSP432 và khóa học / phòng thí nghiệm TI-RSLK, thì hầu như tất cả các chương trình ở trên sẽ quen thuộc với bạn.

Một điều mới mà tôi có thể thấy là việc sử dụng "=" khi tải "DEADBEEF" vào để đăng ký R7. Chúng tôi đã không sử dụng nó.

Tệp "core. S" được đính kèm ở đây hiện chứa nguồn hoàn chỉnh.

Bước 8: Biên dịch mã

Đã đến lúc thực hiện một số công việc dòng lệnh. Một cái gì đó có thật, cuối cùng.

Tuy nhiên, chúng tôi không hoàn toàn ở đó. Chúng tôi một lần nữa phải điều chỉnh lệnh được đưa ra trong bài viết và sửa đổi nó theo tình huống của riêng chúng tôi.

Đây là mã ví dụ:

arm-none-eabi-gcc -x assembly-with-cpp -c -O0 -mcpu = cortex-m0 -mthumb -all core. S -o core.o

Nếu chúng tôi truy cập trang gnu.org cho GCC, (trong trường hợp này là phiên bản 7.3),

NS

-X là để chỉ định ngôn ngữ. Ngược lại, nếu không có -x, thì trình biên dịch sẽ cố gắng đoán bằng cách sử dụng phần mở rộng tệp. (trong trường hợp của chúng tôi, *. S).

Ví dụ trên từ bài viết chỉ định trình hợp ngữ-với-cpp, nhưng chúng ta chỉ có thể thực hiện trình hợp dịch.

NS

-C nói rằng biên dịch nhưng không liên kết.

O0

-O là đặt mức tối ưu hóa. Sử dụng -O0 (oh-zero) cho biết "giảm thời gian biên dịch và làm cho việc gỡ lỗi tạo ra kết quả như mong đợi. Đây là mặc định".

mcpu = cortex-m0

-Mcpu chỉ định tên của bộ xử lý đích. Trong trường hợp của chúng tôi, nó sẽ là cortex-m4.

mthumb

-Mthumb chỉ định lựa chọn giữa việc tạo mã thực thi trạng thái ARM và THUMB.

Tường

-Các bức tường tất nhiên là rất phổ biến và nổi tiếng. Nó bật tất cả các cờ cảnh báo.

Cuối cùng, khi kết thúc lệnh, chúng ta có tệp đầu vào core. S và tệp đầu ra core.o.

Đây là dòng lệnh mới kết quả để phù hợp với trường hợp cụ thể của chúng tôi.

trình lắp ráp arm-none-eabi-gcc -x -c -O0 -mcpu = cortex-m4 -mthumb -Call core. S -o core.o

Và điều đó được biên dịch.

Bước 9: Liên kết chương trình

Trực tiếp từ ví dụ trong bài viết, chúng tôi có điều này:

arm-none-eabi-gcc core.o -mcpu = cortex-m0 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./STM32F031K6T6.ld -o main.elf

Hầu hết những điều trên bạn đã thấy. Dưới đây là những gì mới.

-specs = nosys.specs

Điều này là một chút khó khăn để giải thích.

Nó liên quan đến "semihosting" và "nhắm mục tiêu lại", và nó liên quan đến đầu vào / đầu ra. Nó cũng liên quan đến các cuộc gọi hệ thống và thư viện.

Thông thường, các hệ thống nhúng không cung cấp các thiết bị đầu vào / đầu ra tiêu chuẩn. Điều này sẽ ảnh hưởng đến các lệnh gọi hệ thống hoặc thư viện (ví dụ: printf ()).

Semihosting có nghĩa là trình gỡ lỗi (xem hình ảnh Bước 11 với phần trình gỡ lỗi được khoanh đỏ) có một kênh đặc biệt và sử dụng giao thức semihosting và bạn có thể thấy đầu ra của printf () trên máy chủ (thông qua trình gỡ lỗi).

Mặt khác, nhắm mục tiêu lại có nghĩa là các lệnh gọi hệ thống hoặc thư viện rất giống nhau đó có nghĩa là một cái gì đó khác. Họ làm điều gì đó khác, điều đó có ý nghĩa đối với hệ thống nhúng. Theo một nghĩa nào đó, đối với printf (), có một triển khai mới, một triển khai được nhắm mục tiêu lại của hàm đó.

Đã nói tất cả những điều đó, --specs = nosys.specs có nghĩa là chúng ta sẽ không bán ẩn. Điều đó bình thường có nghĩa là chúng tôi đang nhắm mục tiêu lại. Điều đó đưa chúng ta đến thế cờ tiếp theo.

nostdlib

Tùy chọn trình liên kết -nostdlib được sử dụng để liên kết một chương trình dự định chạy độc lập. -nostdlib ngụ ý các tùy chọn riêng lẻ -nodefaultlibs và -nostartfiles. Dưới đây chúng tôi thảo luận riêng về hai tùy chọn, nhưng cách sử dụng điển hình nhất chỉ là nostdlib để mua sắm một lần. strlen và bạn bè). Tùy chọn trình liên kết -nodefaultlibs vô hiệu hóa liên kết với các thư viện mặc định đó; các thư viện duy nhất được liên kết là chính xác những thư viện mà bạn đặt tên rõ ràng cho trình liên kết bằng cách sử dụng cờ -l.

lgcc

libgcc.a là một thư viện chuẩn cung cấp các chương trình con bên trong để khắc phục những thiếu sót của các máy cụ thể. Ví dụ, bộ xử lý ARM không bao gồm lệnh phân chia. Phiên bản ARM của libgcc.a bao gồm một hàm phân chia và trình biên dịch phát ra các lệnh gọi đến hàm đó khi cần thiết.

NS

Đây chỉ là một cách để yêu cầu trình liên kết sử dụng tệp này làm tập lệnh của trình liên kết. Trong trường hợp của chúng tôi, tên tệp là linker.script.ld.

o main.elf

Cuối cùng, chúng tôi cho trình liên kết biết tên của tệp hình ảnh đầu ra cuối cùng sẽ được ghi / chiếu vào thiết bị của chúng tôi.

Đây là phiên bản dòng lệnh hoàn chỉnh của chúng tôi, được sửa đổi cho tình huống cụ thể của chúng tôi:

arm-none-eabi-gcc core.o -mcpu = cortex-m4 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./linker.script.ld -o main.elf

Chúng tôi đảm bảo rằng tệp script và tệp core.o đều nằm trong cùng một thư mục, nơi chúng tôi sẽ chạy dòng lệnh trên.

Và nó liên kết không có vấn đề gì.

A Séc

Sau đó chúng tôi chạy:

arm-none-eabi-nm main.elf

và chúng tôi nhận được:

devchu @ chubox: ~ / Development / Atollic / TrueSTUDIO / STM32_workspace_9.1 $ arm-none-eabi-nm main.elf 20014000 A _estack 08000010 t main_loop 08000008 T reset_handler 08000000 T vtable

Có vẻ tốt. Lệnh arm-none-eabi-nm là một cách để liệt kê các ký hiệu trong các tệp đối tượng.

Bước 10: Kiểm tra Kết nối với STM32 Nucleo-64

Thử nghiệm Kết nối với STM32 Nucleo-64
Thử nghiệm Kết nối với STM32 Nucleo-64
Thử nghiệm Kết nối với STM32 Nucleo-64
Thử nghiệm Kết nối với STM32 Nucleo-64

Nhiệm vụ đầu tiên của bạn, nếu bạn chọn chấp nhận nó, là làm cho hệ thống của bạn nhìn thấy bảng phát triển của bạn.

Sử dụng Windows

Đối với Windows, tôi quyết định cài đặt TrueSTUDIO từ Atollic (phiên bản miễn phí). Đó là một cài đặt không đau và nó tự động cài đặt trình điều khiển để tôi có thể sử dụng st-link để kiểm tra kết nối. Sau khi tôi cài đặt TrueSTUDIO và trình quản lý thiết bị nhìn thấy thiết bị, tôi đã tải xuống các công cụ texan / stlink được đề xuất bởi bài viết Bare Metal mà chúng tôi đã theo dõi. Tôi lại đặt thư mục ngay dưới "C: \", và một lần nữa tạo một số liên kết từ thùng máy chủ cygwin cục bộ của tôi đến các lệnh.

ln -s /c/STM32. MCU/stlink-1.3.0-win64/bin/st-info.exe ~ / bin / st-info

Như một thử nghiệm ban đầu để xem liệu chúng tôi có thể thực sự giao tiếp với thiết bị hay không, tôi đã chạy:

st-info --probe

Và nhận lại:

Đã tìm thấy 1 lập trình viên liên kết

Vì vậy, bây giờ chúng tôi biết chúng tôi có thể nói chuyện / truy vấn ban phát triển của chúng tôi.

Sử dụng Linux

Đối với linux, bạn không thực sự cần trình điều khiển. Nhưng đối với Debian, bạn sẽ phải xây dựng các công cụ đầu tiên từ nguồn.

git clone

Đảm bảo rằng bạn đã cài đặt libusb-1.0-0-dev.

danh sách apt | grep -E "* libusb. * dev *"

Bạn nên thấy:

libusb-1.0-0-dev / xenial, hiện là 2: 1.0.20-1 amd64 [đã cài đặt]

hoặc điều tương tự.

Để cài đặt nó:

sudo apt-get install libusb-1.0-0-dev

Lưu ý rằng những điều trên không giống như:

sudo apt-get install libusb-dev

Thiếu libusb dev chính xác có thể khiến cmake gặp sự cố.

Lỗi CMake: Các biến sau được sử dụng trong dự án này, nhưng chúng được đặt thành NOTFOUND. Vui lòng đặt chúng hoặc đảm bảo chúng được đặt và kiểm tra chính xác trong tệp CMake: LIBUSB_INCLUDE_DIR (ADVANCED)

Thay đổi thư mục gốc của dự án (… blah / blah / stlink). Thực hiện một "thực hiện phát hành".

Sau khi xây dựng, các công cụ phải ở dưới ".. / build / Release".

Sau đó, bạn có thể chạy "st-info --probe". Đây là đầu ra với Nucleo được kết nối, sau đó không phải.

devchu @ chubox: ~ / Development / stlink $./build/Release/st-info --probeFound 1 chuỗi lập trình viên stlink: 303636414646353034393535363537 openocd: "\ x30 / x36 / x36 / x41 / x46 / x46 / x35 / x30 / x34 / x39 / x35 / x35 / x36 / x35 / x37 "flash: 524288 (kích thước trang: 2048) sram: 65536 chipid: 0x0446 descr: F303 thiết bị mật độ cao devchu @ chubox: ~ / Development / stlink $./build/Release/st- info --probe Đã tìm thấy 0 lập trình viên stlink devchu @ chubox: ~ / Development / stlink $

Bước 11: Hãy sử dụng GDB với Linux

Hãy sử dụng GDB với Linux
Hãy sử dụng GDB với Linux
Hãy sử dụng GDB với Linux
Hãy sử dụng GDB với Linux

Nếu bạn đã cố gắng tất cả những điều này, và bạn đã đạt được điều này - thật tuyệt! Xuất sắc. Hãy vui vẻ một chút ngay bây giờ.

Khi bạn mua các bảng phát triển ARM này, cho dù chúng là MSP432 Launchpad từ Texas Instruments hay cái mà chúng ta đang thảo luận bây giờ, Nucleo-F303 (STM32 Nucleo-64), chúng thường đến với một chương trình đang chạy, thường là một số chương trình nhấp nháy cũng bao gồm việc nhấn công tắc để thay đổi tốc độ (các) đèn LED nhấp nháy.

Trước khi viết quá nhanh, chúng ta hãy xem những gì cần xem và làm.

Với Linux, hãy mở một thiết bị đầu cuối, thay đổi thư mục của dự án stlink git mà chúng tôi vừa tạo và tìm công cụ st-use.

devchu @ chubox: ~ / Development / stlink $ find. -name st-use

./build/Release/src/gdbserver/st-util

Chạy công cụ đó. Vì trước đây chúng tôi đã kiểm tra kết nối của mình với st-info --probe, chúng tôi sẽ nhận được một số đầu ra như sau:

devchu @ chubox: ~ / Development / stlink $./build/Release/src/gdbserver/st-util

st-use 1.4.0-50-g7fafee2 2018-10-20T18: 33: 23 INFO common.c: Thông số thiết bị đang tải…. 2018-10-20T18: 33: 23 INFO common.c: Thiết bị được kết nối là: thiết bị mật độ cao F303, id 0x10036446 2018-10-20T18: 33: 23 INFO common.c: Kích thước SRAM: 0x10000 byte (64 KiB), Flash: 0x80000 byte (512 KiB) trong các trang 2048 byte 2018-10-20T18: 33: 23 INFO gdb-server.c: ID chip là 00000446, ID lõi là 2ba01477. 2018-10-20T18: 33: 23 THÔNG TIN gdb-server.c: Đang nghe tại *: 4242…

Đó là máy chủ GDB đang chạy và nó nhìn thấy bảng phát triển của chúng tôi, và quan trọng hơn, nó đang lắng nghe trên cổng 4242 (cổng mặc định).

Bây giờ chúng tôi đã sẵn sàng để kích hoạt ứng dụng GDB.

Trong Linux, hãy mở một thiết bị đầu cuối khác, nhập vào:

arm-none-eabi-gdb -tui

Điều đó cũng giống như chạy dòng lệnh của gdb, tuy nhiên thay vào đó nó tạo ra một thiết bị đầu cuối dựa trên văn bản (tôi đoán là nó sử dụng các lời nguyền).

Chúng tôi có ứng dụng khách GDB và máy chủ GDB đang chạy. Tuy nhiên, máy khách không được kết nối với máy chủ. Hiện tại, nó không biết gì về Nucleo của chúng tôi (hoặc hội đồng quản trị mà bạn lựa chọn). Chúng ta phải nói với nó. Trong terminal, lời nhắc của bạn bây giờ phải là "(gdb)". Vào:

mục tiêu trợ giúp

Nó sẽ cung cấp cho bạn một danh sách. Lưu ý rằng cái mà chúng tôi muốn là nhắm mục tiêu từ xa mở rộng - Sử dụng máy tính từ xa thông qua một đường dây nối tiếp.

Nhưng chúng tôi cũng phải cung cấp cho nó vị trí. Vì vậy, tại dấu nhắc (gdb), hãy nhập:

(gdb) nhắm mục tiêu máy chủ cục bộ từ xa mở rộng: 4242

Bạn sẽ nhận được phản hồi như sau:

(gdb) nhắm mục tiêu máy chủ cục bộ từ xa mở rộng: 4242

Gỡ lỗi từ xa bằng cách sử dụng localhost: 4242 0x080028e4 trong ?? ()

Trong khi đó, tại thiết bị đầu cuối đang chạy trình gdbserver st-use, chúng tôi nhận được điều này:

2018-10-20T18: 42: 30 THÔNG TIN Gdb-server.c: Đã tìm thấy các đăng ký điểm ngắt 6 giờ

2018-10-20T18: 42: 30 THÔNG TIN gdb-server.c: Đã kết nối GDB.

Bước 12: Hãy lặp lại, với Windows và Flash Chương trình của chúng tôi

Hãy lặp lại, với Windows và Flash Chương trình của chúng tôi
Hãy lặp lại, với Windows và Flash Chương trình của chúng tôi
Hãy lặp lại, với Windows và Flash Chương trình của chúng tôi
Hãy lặp lại, với Windows và Flash Chương trình của chúng tôi
Hãy lặp lại, với Windows và Flash Chương trình của chúng tôi
Hãy lặp lại, với Windows và Flash Chương trình của chúng tôi

Các bước để chạy máy chủ st-use gdbserver và máy khách arm-none-eabi-gdb về cơ bản giống như chúng ta đã làm trong Bước trước. Bạn mở hai thiết bị đầu cuối (cygwin, DOS cmd hoặc Windows Powershell), tìm vị trí của thiết bị đầu cuối, chạy nó. Trong thiết bị đầu cuối khác, chạy ứng dụng arm-none-eabi-gdb. Sự khác biệt duy nhất là chế độ -tui (chế độ xem văn bản dựa trên thiết bị đầu cuối) rất có thể không được hỗ trợ.

Nếu cách trên hoạt động trong Windows, thì có thể bạn sẽ phải dừng (chỉ ứng dụng khách). Tại thời điểm này, bằng cách nào đó, bạn sẽ cần chạy ứng dụng khách GDB nơi tệp xây dựng của bạn ("core.out") hoặc thêm toàn bộ đường dẫn đến tệp đó làm đối số cho ứng dụng khách GDB.

Tôi đã đơn giản hóa cuộc sống của mình bằng cách sử dụng cygwin và tạo các liên kết từ thư mục $ HOME // bin cục bộ của tôi đến nơi cả hai công cụ đó đều nằm.

Được rồi, chúng tôi đã biên dịch và liên kết giống như trước đây và chúng tôi có tệp main.elf đã sẵn sàng để được flash.

Chúng tôi có st-use đang chạy trong một cửa sổ. Chúng tôi khởi động lại ứng dụng GDB, lần này chúng tôi thực hiện:

arm-none-eabi-gdb main.elf

Chúng tôi để nó khởi động, đợi lời nhắc (gdb), thực hiện lệnh kết nối tương tự của chúng tôi với máy chủ GDB (st-use) và chúng tôi đã sẵn sàng flash tệp thực thi. Nó rất chống khí hậu:

(gdb) tải

Chạy với các thiết bị đầu cuối cygwin, có một vấn đề đã biết là đôi khi các lệnh của bảng điều khiển không xuất hiện. Vì vậy, trong trường hợp của chúng tôi, cửa sổ chạy máy chủ hoàn toàn im lặng. Trình chạy máy khách, nơi chúng tôi chạy tải, xuất ra:

Đang tải phần.text, kích thước 0x1c lma 0x8000000Địa chỉ bắt đầu 0x8000000, kích thước tải 28 Tốc độ truyền: 1 KB / giây, 28 byte / lần ghi.

Bước 13: Nhấp nháy với Linux - Thêm phần thưởng: D

Nhấp nháy với Linux - Nhiều phần thưởng hơn: D
Nhấp nháy với Linux - Nhiều phần thưởng hơn: D

Bước 14: Hãy lặn sâu hơn một chút

Nếu bạn đến được đây, thật xuất sắc. Tiếp tục nào.

Tại sao không nhìn vào bên trong tệp main.elf, tệp thực thi? Chạy như sau:

arm-none-eabi-objdump -d main.elf

Bạn sẽ thấy một kết quả như thế này:

main.elf: định dạng tệp elf32-littlearm

Tháo gỡ phần.text:

08000000:

8000000: 00 40 01 20 09 00 00 08.@. ….

08000008:

8000008: 4802 ldr r0, [pc, # 8]; (8000014) 800000a: 4685 mov sp, r0 800000c: 4f02 ldr r7, [pc, # 8]; (8000018) 800000e: 2000 mov r0, # 0

08000010:

8000010: 3001 thêm r0, # 1 8000012: e7fd b.n 8000010 8000014: 20014000.word 0x20014000 8000018: deadbeef.word 0xdeadbeef

Chúng ta có thể thu được ít cốm gì từ sản lượng trên?

Nếu bạn nhớ lại khi chúng ta thảo luận và tạo tệp linker.script.ld, chúng tôi đã nói rằng các thiết bị ARM này có RAM bắt đầu từ 0x20000000 và bộ nhớ FLASH đó bắt đầu từ 0x08000000.

Do đó, chúng ta có thể thấy rằng chương trình thực sự là như vậy mà tất cả đều nằm trong bộ nhớ FLASH.

Sau đó, ở trên, nhưng ở Bước sau, khi chúng tôi đang bỏ qua phần "Hello World", có một câu lệnh trong đó chúng tôi tải một giá trị ngay lập tức, không đổi, theo nghĩa đen ("0xDEADBEEF") vào thanh ghi lõi MCU ("R7").

Tuyên bố là:

LDR R7, = 0xDEADBEEF

Trong mã của chúng tôi, đó là nơi duy nhất mà chúng tôi thậm chí đề cập đến DEADBEEF. Không ở đâu khác. Chưa hết, nếu bạn nhìn vào các hướng dẫn tháo rời / tái tạo ở trên, v.v., có nhiều thứ liên quan đến DEADBEEF hơn chúng ta nghĩ.

Vì vậy, bằng cách nào đó, trình biên dịch / trình liên kết đã quyết định cài đặt vĩnh viễn giá trị của DEADBEEF vào một địa chỉ FLASH, tại vị trí 0x8000018. Và sau đó, trình biên dịch đã thay đổi hướng dẫn LDR ở trên của chúng tôi thành:

LDR R7, [PC, # 8]

Nó thậm chí còn tạo ra một bình luận cho chúng tôi. Thật tuyệt. Và nó yêu cầu chúng ta lấy giá trị bộ đếm chương trình hiện tại (thanh ghi PC), thêm 0x8 vào giá trị đó, và đó là nơi DEADBEEF đã được ghi, và lấy giá trị đó và nhét nó vào R7.

Vì vậy, điều đó cũng có nghĩa là bộ đếm chương trình (PC) đã trỏ đến địa chỉ 0x8000010, là nơi bắt đầu của main_loop và giá trị DEADBEEF nằm ở hai địa chỉ sau khi kết thúc main_loop.

Bước 15: Cuối cùng, hãy xem sơ qua chương trình đang chạy

Ngay cả khi bạn thoát khỏi GDB, chỉ cần nhập lại lệnh. Bạn thậm chí không phải cung cấp cho nó bất kỳ tệp nào; chúng tôi không nhấp nháy nữa, chỉ chạy nó.

Khi bạn đã kết nối lại ứng dụng khách GDB với máy chủ GDB, tại dấu nhắc lệnh (gdb):

(gdb) đăng ký thông tin

Bạn sẽ thấy một cái gì đó như thế này:

r0 0x0 0

r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20014000 0x20000014000 lr 0xffff00ffff

Nhưng sau đó, tại dấu nhắc (gdb), hãy nhập:

(gdb) tiếp tục

Và rất nhanh chóng nhấn CTRL-C. Điều đó sẽ tạm dừng chương trình. Nhập lại lệnh "sổ đăng ký thông tin".

Lần này, có vẻ khác:

(gdb) đăng ký thông tin

r0 0x350ffa 3477498 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0xdeadbeef 3735928559 r8 0x0 0 r9 0x0 0 r10 0x0 0 rff11 0x0 0 r12 0x0 0 0x800 16777216

Chuyện gì đã xảy ra thế? Chính xác những gì chúng tôi muốn. DEADBEEF đã được nạp vào R7 và R0 đang tăng (cực nhanh). Nếu lặp lại, bạn sẽ gặp lại R0 với giá trị khác.

Bước 16: Chúng tôi muốn tạo một mảng chỉ đọc trong Flash

Một cách để tạo mảng tương đương bằng cách sử dụng hợp ngữ và chỉ thị, như sau:

.type myarray,% object // tên hoặc nhãn 'myarray' được định nghĩa là một kiểu đối tượng.

myarray: // đây là phần bắt đầu của khai báo 'myarray' // (nó sẽ bao gồm những gì)..word 0x11111111 // thành viên hoặc giá trị đầu tiên có trong 'myarray'..word 0x22222222 // giá trị thứ hai (các địa chỉ liền nhau)..word 0x33333333 // và v.v..size myarray,.-myarray // trình biên dịch / hợp ngữ hiện biết vị trí kết thúc hoặc // ranh giới của 'myarray'.

Bây giờ chúng ta đã thiết lập nó trong bộ nhớ FLASH, chúng ta có thể sử dụng nó trong chương trình. Dưới đây là một phần:

LDR R1, myarray // cái này tải dữ liệu có ở vị trí đầu tiên của 'myarray'. ' // đây không phải là những gì chúng ta muốn.

LDR R1, = myarray // điều này tự tải giá trị vị trí (địa chỉ đầu tiên), // không phải dữ liệu.. // đây là thứ chúng ta muốn.

MOV R2, # 0 // R2 sẽ giữ một số đếm để đảm bảo rằng chúng ta không đi chệch hướng

// kết thúc mảng. LDR R3, = myarrsize // R3 sẽ tương đương với 'myarrsize'.

// R0 sẽ giữ dữ liệu của chúng ta

vòng lặp chính:

LDR R0, [R1] // Tải dữ liệu được trỏ tới bởi R1 ('myarray') vào R0. CMP R2, R3 // Chúng ta có đang ở giới hạn của mảng không? BEQ main_loop // Nếu có, chúng ta đã hoàn tất, vì vậy chúng ta sẽ lặp lại mãi mãi.

ADD R2, # 1 // Nếu không, chúng ta có thể tiếp tục lặp qua mảng.

THÊM R1, # 4 // Thêm 4 vào thanh ghi R1, vì vậy nó trỏ chính xác đến tiếp theo

// Địa chỉ..

B main_loop // Lặp lại.

Video nói về tất cả những điều này, và có một lỗi trong đó. Nó tốt; nó cho thấy rằng đó là mã chạy và gỡ lỗi quan trọng. Nó cho thấy một trường hợp cổ điển là đi ra khỏi phần cuối của một mảng.

Đề xuất: