Làm thế nào để thực hiện chuyển đổi ngăn xếp đơn giản trong lõi PIC12 / 16?


7

Tôi đang cố gắng để hiểu làm thế nào hệ điều hành thời gian thực hoạt động. Tôi đã xem xét mã nguồn của một số RTOS. Tôi muốn tìm hiểu bằng cách tạo RTOS đơn giản của mình, một cái gì đó giống như FLIRT .

Tôi đang sử dụng trình biên dịch PIC16 và XC8 C với MPLABX. Tôi cũng muốn thực hiện loạt RTOS rất đơn giản này đến PIC12.

Vì vậy, tôi quyết định rằng tôi nên bắt đầu bằng cách học cách thao tác ngăn xếp (như supercat đã làm trong câu trả lời này ) và tôi bắt đầu tìm kiếm và tìm thấy AN818 có tiêu đề "Thao tác ngăn xếp của vi điều khiển PIC18". Trích dẫn từ ghi chú của ứng dụng:

Theo truyền thống, ngăn xếp vi điều khiển chỉ được sử dụng làm không gian lưu trữ cho các địa chỉ trả về của chương trình con hoặc các thói quen ngắt, trong đó tất cả các hoạt động 'đẩy' và 'pop' đều bị ẩn.

Đối với hầu hết các phần, người dùng không có quyền truy cập trực tiếp vào thông tin trên ngăn xếp. Vi điều khiển PIC18 hơi khác với truyền thống này. Với lõi PIC18 mới, giờ đây người dùng có quyền truy cập vào ngăn xếp và có thể sửa đổi trực tiếp con trỏ ngăn xếp và ngăn xếp dữ liệu.

Tôi bị bối rối. Tại sao có RTOS được tạo cho vi điều khiển PIC hoạt động với lõi PIC16? Ví dụ, OSA RTOS có sẵn cho PIC12 / 16 với trình biên dịch mikroC.

Bạn có thể hướng tôi đến một số tài nguyên, hoặc nếu có thể đưa ra ví dụ, để tôi có thể tìm hiểu về chuyển đổi ngăn xếp?

Câu trả lời:


4

Mỗi RTOS cho PIC không có ngăn xếp có thể định địa chỉ phần mềm thường yêu cầu tất cả ngoại trừ một trong các tác vụ phải phân chia thành các phần không bị gián đoạn bắt đầu và kết thúc ở cấp ngăn xếp trên cùng; hoạt động "năng suất tác vụ" không sử dụng lệnh gọi hàm, mà là một chuỗi như

// Mã này là một phần của nhiệm vụ C (giả sử ví dụ này, có các tác vụ
// gọi là A, B, C
  Movlw JumpC4 & 255
  goto TASK_SWITCH_FROM_C
Mục tiêu 4:

Ở nơi khác trong mã sẽ có một số mã như:

TASK_SWITCH_FROM_A:
  Movwf nextJumpA // Lưu trạng thái của nhiệm vụ C
  // Bây giờ gửi hướng dẫn tiếp theo cho nhiệm vụ A
  Movlw TaskB_Table >> 8
  Movwf PCLATH
  Movf nextJumpB, w
  di chuyển PCL
TASK_SWITCH_FROM_B:
  Movwf nextJumpB // Lưu trạng thái của nhiệm vụ C
  // Bây giờ gửi hướng dẫn tiếp theo cho nhiệm vụ A
  nhiệm vụ Movlw >> 8
  Movwf PCLATH
  Movf nextJumpC, w
  di chuyển PCL
TASK_SWITCH_FROM_C:
  Movwf nextJumpC // Lưu trạng thái của nhiệm vụ C
  // Bây giờ gửi hướng dẫn tiếp theo cho nhiệm vụ A
  Movlw TaskA_Table >> 8
  Movwf PCLATH
  Movf nextJumpA, w
  di chuyển PCL

Ở cuối mã, cho mỗi nhiệm vụ, sẽ có một bảng nhảy; mỗi bảng sẽ phải vừa trong một trang 256 từ (và do đó có thể có tối đa 256 lần nhảy)

Nhiệm vụ:
JumpC0: goto TargetC0
JumpC1: goto TargetC1
JumpC2: goto TargetC2
JumpC3: goto TargetC3
JumpC4: goto TargetC4
...Vân vân.

Thực tế, movlwkhi bắt đầu chuỗi chuyển đổi tác vụ tải thanh ghi W với LSB của địa chỉ của lệnh tại JumpC4. Mã tại TASK_SWITCH_FROM_Csẽ bỏ giá trị đó ở một nơi nào đó và sau đó gửi mã cho tác vụ A. Sau đó, sau khi TASK_SWITCH_FROM_Bđược thực thi, JumpC4địa chỉ được lưu trữ sẽ được tải lại vào W và hệ thống sẽ chuyển đến hướng dẫn được chỉ ra từ đó. Lệnh đó sẽ là một goto TargetC4, lần lượt tiếp tục thực hiện tại lệnh theo trình tự chuyển đổi tác vụ. Lưu ý rằng chuyển đổi tác vụ hoàn toàn không sử dụng ngăn xếp.

Nếu một người muốn thực hiện một chuyển đổi tác vụ trong một hàm được gọi, thì có thể làm như vậy nếu lệnh gọi và trả về của hàm đó được xử lý theo cách tương tự như trên (có lẽ người ta phải bọc lệnh gọi hàm trong một macro đặc biệt để buộc mã thích hợp được tạo ra). Lưu ý rằng trình biên dịch sẽ không có khả năng tạo mã như trên. Thay vào đó, các macro trong mã nguồn sẽ tạo ra các lệnh trong tệp ngôn ngữ hợp ngữ. Một chương trình được cung cấp bởi nhà cung cấp RTOS sẽ đọc tệp ngôn ngữ lắp ráp, tìm kiếm các chỉ thị đó và tạo mã vectơ thích hợp.


Tôi không thể hiểu mã ngoại trừ từ phần cài đặt PCLATH. JUMPCx và TargetCx là gì? Di chuyển JumpC4 & 255đến W làm gì?
abdullah kahraman

Cảm ơn đã chỉnh sửa! Sẽ tốt hơn nếu bạn chú ý đến tôi về nó :) Theo như tôi hiểu, ở mỗi năng suất trong một nhiệm vụ, có một mục tiêu trở lại tại bàn của nhiệm vụ. Đây là những gì tôi làm trong C bây giờ, một cái gì đó rất giống với điều này . Tôi không hiểu tại sao cần phải có các bảng? Đây trang cho thấy rằng nó có thể được thực hiện chỉ sử dụng một biến mỗi công việc, hoặc hai nếu có phân trang.
abdullah kahraman

1
Có một số cách tiếp cận hơi khác nhau mà người ta có thể sử dụng để đạt được đa nhiệm trên PIC. Ưu điểm của cách tiếp cận bảng nhảy là nó sử dụng các biến đơn byte để theo dõi bước tiếp theo của mỗi tác vụ, nhưng vẫn cho phép bản thân các tác vụ sử dụng mã trị giá 2K. Nếu mã cho mỗi tác vụ sẽ phù hợp với trang 256 byte, người ta có thể từ bỏ bảng nhảy. Ngoài ra, nếu không muốn sử dụng bảng nhảy, người ta có thể sử dụng các biến hai byte cho mỗi 'bước tiếp theo' của mỗi tác vụ, nhưng mã chuyển đổi tác vụ trở nên chậm hơn và cồng kềnh hơn.
supercat

Đối với việc sử dụng movlw/gotoso với retlw, cái sau tiết kiệm một từ không gian mã cho mỗi chuyển đổi tác vụ, nhưng cuối cùng lại chậm hơn một chu kỳ do cần phải callcó "bàn đạp". Đáng kể hơn, khi sử dụng movlw/goto, một nhiệm vụ có thể thực hiện chuyển đổi tác vụ từ trong các thói quen lồng nhau; nếu ai đó hạn chế sử dụng các retlwnhiệm vụ không cần chuyển đổi từ trong các thói quen lồng nhau, điều đó sẽ ổn, nhưng việc trộn các mô hình chuyển đổi nhiệm vụ có thể gây thêm nhầm lẫn.
supercat

4

Các PIC lõi 14 bit truyền thống (chủ yếu là PIC 16 và một vài PIC 12) không có cách nào để chương trình truy cập vào ngăn xếp cuộc gọi. Điều này do đó làm cho một hệ thống đa tác vụ thực sự là không thể.

Tuy nhiên, bạn vẫn có thể có những gì tôi gọi là nhiệm vụ giả. Đây là một thói quen được gọi định kỳ từ vòng lặp sự kiện chính. Nó duy trì một địa chỉ khởi động lại trong nội bộ. Khi vòng lặp chẵn chính gọi nó, nó sẽ nhảy đến địa chỉ khởi động lại của tác vụ giả riêng tư với mô-đun đó. Sau một số xử lý, mã tác vụ gọi macro YIELD đặt địa chỉ khởi động lại ngay sau macro, sau đó trả về từ cuộc gọi ban đầu. Vì ngăn xếp cuộc gọi không thể mở ra, YIELD chỉ có thể được gọi từ cấp độ nhiệm vụ hàng đầu. Tuy nhiên, đây là một trừu tượng hữu ích.

Bạn có thể thấy một ví dụ về một tác vụ giả như vậy đang được sử dụng để xử lý luồng lệnh từ máy tính chủ trong mô-đun mẫu QQQ_CMD.ASPIC của tôi. Trong trường hợp này, việc trả về cho người gọi bị ẩn trong macro GETBYTE, xuất hiện để đi và nhận byte đầu vào tiếp theo từ quan điểm của nhiệm vụ. Cài đặt bản phát hành Công cụ phát triển PIC của tôi từ trang tải xuống phần mềm . QQQ_CMD.ASPIC sẽ nằm trong thư mục SOURCE> PIC trong thư mục cài đặt phần mềm.

Để xem cách thực hiện đa tác vụ thực sự khi bạn có quyền truy cập vào ngăn xếp cuộc gọi, hãy xem TASK.INS.ASPIC trong cùng thư mục. Đó là hệ thống đa tác vụ chung của tôi cho PIC 18. Bạn có thể thấy điều tương tự đối với kiến ​​trúc DSPIC bằng cách xem TASK.INS.DSPIC trong thư mục SOURCE> DSPIC.


Có vẻ như tôi phải bắt đầu học lắp ráp.
abdullah kahraman

@abdullah: Có, bạn cần ngôn ngữ lắp ráp để thực hiện các hành động không tự nhiên trên ngăn xếp, điều cần thiết trong hầu hết các sơ đồ chuyển đổi nhiệm vụ. Ít nhất bạn cũng phải hiểu lắp ráp để biết những gì đang diễn ra ở cấp độ thấp, ngay cả khi bạn lập trình bằng ngôn ngữ cấp cao. Trên vi điều khiển, bạn không thể bỏ qua chi tiết phần cứng. Nó không giống như trên một hệ thống mục đích chung lớn, nơi có nhiều lớp trừu tượng giữa bạn và phần cứng. Tất cả các EE sử dụng vi điều khiển phải biết lắp ráp.
Olin Lathrop

Tôi nghĩ rằng tôi không cần phải ghi nhớ tất cả các hướng dẫn và như vậy, tất cả chúng đều nằm trong bảng dữ liệu. Những gì tôi nên hiểu là các chi tiết phần cứng. Tôi đã xem xét GETBYTEvĩ mô nhưng không thể hiểu bất cứ điều gì cả. Tôi sẽ lấy lại nó sau. Bây giờ, tôi đang xem Pic'Xe và tôi có thể hiểu lắp ráp khi tôi lướt qua bảng dữ liệu. Tuy nhiên, tôi không hiểu ý nghĩa của FSR và INDF, v.v., đó là phần cứng. Vì vậy, bây giờ tôi đang theo hướng dẫn kiến ​​trúc PIC x14 ở đây .
abdullah kahraman

@abdullah: Bạn không hiểu phần nào của GETBYTE? Tôi có thể đi qua nó, nhưng câu hỏi cụ thể sẽ giúp. Lưu ý rằng mã của tôi giả sử các macro được xác định trong STD.INS.ASPIC và cũng được chạy qua bộ tiền xử lý của tôi (PREPIC, được mô tả trong thư mục DOC) trước khi MPASM nhìn thấy bất kỳ mã nào. Tôi chỉ nhìn vào GETBYTE và nó sử dụng một số macro của tôi (DBANKIF, JUMP, v.v.), nhưng không phải là bộ tiền xử lý.
Olin Lathrop

Ah, thật sự quá khó để tôi hiểu GETBYTE. Tuy nhiên, điều tôi hiểu từ macro YIELD là nó lưu địa chỉ khởi động lại của hàm, ngay sau macro, vào ngăn xếp của hàm. Khi xảy ra kích hoạt chuyển đổi tác vụ, nó sẽ tải PC với địa chỉ khởi động lại của tác vụ tiếp theo. Điều tôi hiểu là nếu tôi không cần bất kỳ chuyển đổi tác vụ nào trong các thường trình con, điều mà tôi chưa bao giờ làm, thì đây thực sự là kỹ thuật tương tự với chuyển đổi ngăn xếp.
abdullah kahraman

2

Các chip "lõi 14 bit" của PIC16 có "RAM ngăn xếp phần cứng" hoàn toàn tách biệt và độc lập với "RAM dữ liệu". (Nó thậm chí có kích thước và chiều rộng khác với RAM dữ liệu). "Sơ đồ khối lõi" cho bất kỳ chip nào trong số đó cho thấy rõ rằng "ngăn xếp phần cứng" chỉ được kết nối với bộ đếm chương trình - lệnh duy nhất ghi vào ngăn xếp phần cứng đó là (các loại khác nhau) CALL và chỉ lệnh duy nhất đọc từ ngăn xếp phần cứng đó là (các loại khác nhau) TRẢ LẠI.

"chuyển đổi ngăn xếp" là không thể đối với "ngăn xếp phần cứng" trong các chip "lõi 14 bit" này.

Điều này làm cho hầu hết các phương thức chuyển đổi tác vụ hệ điều hành truyền thống không thể thực hiện được trên loạt chip này.

Có một vài RTOS chạy trên loạt chip này, do đó phải có một vài phương thức chuyển đổi tác vụ có thể có trên chip này ( "Phương pháp đa nhiệm cụ thể của vi điều khiển PIC" ).

Trong thực tế, tất cả các RTOS mà tôi đã thấy đều có một số loại trình chuyển đổi tác vụ hợp tác "mang lại" từ một nhiệm vụ này sang nhiệm vụ tiếp theo chỉ trong mã cấp cao nhất của mỗi nhiệm vụ. Bởi vì năng suất không bao giờ từ bên trong một chương trình con, không có địa chỉ trả về trên ngăn xếp phần cứng.

Về nguyên tắc, có thể lập trình các chip này để xây dựng một ngăn xếp phần mềm trong RAM và sử dụng nó để mô phỏng ngăn xếp trả về. (Sử dụng "ngăn xếp do người dùng xác định" trong RAM dữ liệu, thay vì ngăn xếp phần cứng). Sau đó, bạn có thể sử dụng tất cả các công cụ chuyển đổi tác vụ truyền thống của hệ điều hành, chẳng hạn như cung cấp cho mỗi tác vụ một khối RAM riêng cho ngăn xếp cục bộ của nó, v.v. Tôi không biết liệu các chuỗi cuộc gọi không chuẩn và phức tạp thêm có đáng không.


Cảm ơn thông tin chung và các liên kết. Các liên kết đã giúp rất nhiều.
abdullah kahraman
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.