Thông báo

Collapse
No announcement yet.

Lập trình ngắt trong PSOC

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • #16
    Cái này là của Mrzee. Country: Unknow
    Nhân tiện các bác cho hỏi là trong PSoC thì khi đã rơi vào 1 ngắt rồi thì có thể tiếp tục nhảy vào ngắt khác được không?(Kiểu ngắt trong ngắt ấy)
    Cụ thể về ưu tiên ngắt là thế nào?(không phải là 2 ngắt cùng xảy ra thì dùng thanh ghi INT_MSK để biến 1 ngắt thành pending đâu).

    Comment


    • #17
      Tôi đọc hoài trong Technical Reference Manual mà không thấy nói, có lẽ là không có.

      Comment


      • #18
        Nguyên văn bởi escapevn
        Cái này là của Mrzee. Country: Unknow
        Nhân tiện các bác cho hỏi là trong PSoC thì khi đã rơi vào 1 ngắt rồi thì có thể tiếp tục nhảy vào ngắt khác được không?(Kiểu ngắt trong ngắt ấy)
        Cụ thể về ưu tiên ngắt là thế nào?(không phải là 2 ngắt cùng xảy ra thì dùng thanh ghi INT_MSK để biến 1 ngắt thành pending đâu).
        Thông thường thì ngắt trong ngắt của PSoC ko xảy ra bởi lẽ sau khi chuẩn bị vào trình phục vu ngắt, lập tức GIE được phần cứng xóa =0. Cụ thể hơn:
        Khi có yêu cầu ngắt, thì nó sẽ hoàn thành nốt lệnh hiện tại, sau đó:
        - Lưu byte high cao, byte low của bộ đếm chương trình và thanh ghi cờ (CPU_F) vào Stack .
        - Thanh ghi cờ được xoá , bit GIE được xoá = 0. Do đó những ngắt mới sinh hay đã sinh tạm thời bị cấm.
        - .....
        -Thực thi chương trình phục vụ .
        -Khi trình phục vụ ngắt kết thúc với câu lệnh RETI --->thanh ghi cờ (CPU_F), byte thấp và byte cao của bộ đếm chương trình được lấy ra khỏi Stack.Thanh ghi cờ (CPU_F) được khôi phục lại giá trị đồng thời nó sẽ cho phép các ngắt (GIE=1).

        Những ai quan tâm tới việc thời gian thực nhảy vào ngăt thì chú ý, để vào trình phục vụ ngắt, tiêu tốn ít nhất 13 chu kỳ máy. Vì nó phải thực thi lệnh hiện tai nên con số thực tế có thể hơn 13 chu kỳ máy chút ít.

        Có thể sử dụng kỹ thuật ngắt trong ngắt bằng cách đặt bit GIE=1 trong trình phục vụ ngắt. Nhưng cực kỳ cẩn thận, nó có thể xảy ra việc tràn stack.
        Ví dụ: ngắt
        Onchange()
        {
        GIE=1;
        //code
        }

        Nếu liên tục sự kiện ngắt Onchange() được yêu cầu thì chắc chắn tràn stack
        Tuy nhiên, nếu sư kiện ngăt đó xuất hiện (trong hàm ngăt đó co dong lệnh GIE=1) dài hơn thời gian trình phục vụ thì ko sao. Ví dụ:
        Timer()
        {
        GIE=1;
        //code
        //thời gian thực hiện ngắt mất 1ms
        }
        Nếu chu kỳ ngắt timer>1ms thì ko ko sao, ngược lại se tràn stack.

        Đây là nói riêng PSoC, một số VĐK khác cũng có cơ chế giống hệt như thế này(ví dụ PIC). Chỉ một số thằng như 89 thì có khác.

        Comment


        • #19
          Chính xác. Cái này có viết khá rõ trong Technical Reference trang 74 tuy nhiên em chưa hiểu về cái cơ chế ưu tiên ngắt của nó. Sau khi đã rơi vào ngăt rồi thì phải disable ngắt đó ư? và phải thiết lập lại các thanh ghi điều khiển và mặt nạ ngắt cho ngắt mong đợi tiếp theo? Có lẽ trong PSoC không có chế độ này và phải làm manual thôi.

          Comment


          • #20
            Tất nhiên nếu nhiều ngắt đồng thời xuất hiện, nó sẽ phục vụ ngăt được ưu tiên trước trong bảng vector ngắt. Sau đây là bảng vector ngắt của: 8c27443

            Mức ưu tiên ngắt-Địa chỉ ngắt--------------Tên ngắt
            0(Cao nhất)-------0000h---------------------Reset
            1--------------------0004h--------------------Supply Voltage Monitor
            2--------------------0008h--------------------Analog Column 0
            3--------------------000Ch--------------------''---------------'' 1
            4--------------------0010h--------------------''---------------'' 2
            5--------------------0014h--------------------''---------------'' 3
            6--------------------0018h--------------------VC3
            7--------------------001Ch--------------------GPIO
            8--------------------0020h--------------------PSOC Block DBB 00
            9--------------------0024h--------------------''----------------'' 01
            10-------------------0028h--------------------''----------------'' 02
            11-------------------002Ch--------------------''----------------'' 03
            12-------------------0030h--------------------''----------------'' 10
            13-------------------0034h--------------------''----------------'' 11
            14-------------------0038h--------------------''----------------'' 12
            15-------------------003Ch--------------------''----------------'' 13
            24-------------------0060h--------------------I2C
            25(thấp nhất)----0064h--------------------Sleep Timer

            Comment


            • #21
              Oh cái này chỉ là địa chỉ ngắt trong bảng vector ngắt. Còn 1 ngắt muốn trở thành pending thì phải thiết lập trong INT_MSK_REG.

              Comment


              • #22
                Nguyên văn bởi escapevn
                tuy nhiên em chưa hiểu về cái cơ chế ưu tiên ngắt của nó. Sau khi đã rơi vào ngăt rồi thì phải disable ngắt đó ư? và phải thiết lập lại các thanh ghi điều khiển và mặt nạ ngắt cho ngắt mong đợi tiếp theo? Có lẽ trong PSoC không có chế độ này và phải làm manual thôi.
                Không cần disable ngắt đó, bởi khi trình phục vụ ngắt, GIE tự động bị xóa=0, nên nó chỉ phục vụ ngăt hiên tai đó thôi.
                Em xem kỹ đoạn anh viết ở trên, vì khi vào ngắt, phần cứng sẽ tự động xóa cờ ngắt toàn cục: GIE=0. Bởi vậy, nó sẽ ko thực hiện bất cứ một ngắt khác(trừ ngắt kiểu reset ) cho dù mức ưu tiên cao hơn hay thấp hơn. Bởi lẽ GIE=0 mất rồi. Khi thoát khỏi ngắt, nó mới tự động đặt GIE=1. Lúc này nó tiếp tục phục vụ những ngắt khác. Nếu trong trình phục vụ ngăt đặt GIE=1 thì nó mới có thể ngắt trong ngắt được
                Kiểu ngắt của bọn này khác hẳn với 89 đó. Bọn 89 thì có vẻ hay hơn.

                Comment


                • #23
                  Ok, em đã hiểu ý anh but ý em là khi đó mình phải làm cho ngắt đang thực hiện không posted nữa thì cần phải xóa trong INT_CLR_REG.

                  Comment


                  • #24
                    Nguyên văn bởi escapevn
                    Oh cái này chỉ là địa chỉ ngắt trong bảng vector ngắt. Còn 1 ngắt muốn trở thành pending thì phải thiết lập trong INT_MSK_REG.
                    Thanh ghi INT_MSK là thanh ghi mặt nạ ngắt. Nghĩa là nó cho phép hay ko cho phép ngắt đó. Nếu một bit trong thanh ghi INT_MSKx được set = 1 thì nguồn ngắt kết hợp với bit mặt nạ của nó sẽ sinh ra một ngắt để trở thành ngắt chờ phục vụ. Để ngắtt được thực thi thì: ((Nguồn ngăt đó:i) & (Mặt nạ ngắt:INT_MSKi) ==1), ngoài ra cờ cho phép ngắt toàn cục GIE==1.

                    Comment


                    • #25
                      Nguyên văn bởi escapevn
                      Ok, em đã hiểu ý anh but ý em là khi đó mình phải làm cho ngắt đang thực hiện không posted nữa thì cần phải xóa trong INT_CLR_REG.
                      Ý em là?
                      Ngắt_i()
                      {
                      //Mã lệnh disable ngắt i;
                      .....
                      GIE=1;
                      //Trình phục vụ ngắt
                      .....
                      }
                      ?

                      Ừ, nếu vậy giải pháp này cũng OK đó. Là có thể ngắt trong ngăt nhưng ko sợ tràn stack. Nhưng chú ý đến việc enable lại các ngắt cho hợp lý.
                      Lại còn chuyện nếu ngắt i đó là ngắt ưu tiên hơn, nhưng khi đang thực hiện trình phục vụ ngắt đó, gặp dòng GIE=1; nó sẽ nhảy vào những ngắt bất kỳ j nào đó cho dù ngắt j ít ưu tiên hơn, hay những ngắt ngoài mong muốn xảy ra tại thời điểm đó của em.

                      Comment


                      • #26
                        Nguyên văn bởi BinhAnh
                        Lại còn chuyện nếu ngắt i đó là ngắt ưu tiên hơn, nhưng khi đang thực hiện trình phục vụ ngắt đó, gặp dòng GIE=1; nó sẽ nhảy vào những ngắt bất kỳ j nào đó cho dù ngắt j ít ưu tiên hơn, hay những ngắt ngoài mong muốn xảy ra tại thời điểm đó của em.
                        He he, đúng rồi đó anh. Với lại chỉ là hiếu kì thì bàn về cái này thôi chứ mấy khi dùng đến 3 ngắt đâu anh, ngắt nhiều chỉ tổ loạn, ko kiểm soát nổi.

                        Comment


                        • #27
                          Bác Winter July ui, bác có thể up lên 1 file (đơn giản thôi) mà bác đã làm với ngắt GPIO không, để cho anh em dễ hình dung cách config và các đoạn mã trong đó. Thanks.
                          Tại vì em làm đúng như bác chỉ dẫn mà mình chưa đưa tín hiệu vào thì ngắt đã xảy ra rồi.

                          Comment


                          • #28
                            Nguyên văn bởi calculut
                            Bác Winter July ui, bác có thể up lên 1 file (đơn giản thôi) mà bác đã làm với ngắt GPIO không, để cho anh em dễ hình dung cách config và các đoạn mã trong đó. Thanks.
                            Tại vì em làm đúng như bác chỉ dẫn mà mình chưa đưa tín hiệu vào thì ngắt đã xảy ra rồi.
                            Tốt nhất bạn đưa cái đoạn mã + config đó ra đây, mọi người sẽ chỉ ra cái sai của bạn. Như thế nhanh hơn .

                            Comment


                            • #29
                              Nguyên văn bởi escapevn
                              Với lại chỉ là hiếu kì thì bàn về cái này thôi chứ mấy khi dùng đến 3 ngắt đâu anh, ngắt nhiều chỉ tổ loạn, ko kiểm soát nổi.
                              Nếu 3 ngắt hay nhiều hơn, em thử tham khảo cách anh đưa ra xem sao. Gọi mức ưu tiên của 3 ngắt em mong muốn là 1,2,3 ứng với các hàm Ngắt_1(),Ngắt_2(),Ngắt_3();
                              Mã lệnh được viết như sau:
                              Ngắt_1()
                              {
                              //Chèn mã lệnh: disable ngắt 1,2,3 tại đây
                              GIE=1;
                              //Chèn mã lệnh trình phục vụ ngắt 1
                              }

                              Ngắt_2()
                              {
                              //Chèn mã lệnh: disable ngắt 2,3 tại đây
                              GIE=1;
                              //Chèn mã lệnh trình phục vụ ngắt 2
                              }

                              Ngắt_3()
                              {
                              //Chèn mã lệnh: disable ngắt 3 tại đây
                              GIE=1;
                              //Chèn mã lệnh trình phục vụ ngắt 3
                              }
                              Làm như vậy thì khi vào ngắt i, nó chỉ có thể ngắt trong ngắt với các ngắt có mức ưu tiên cao(<i) hơn theo mình mong muốn. Sau khi rời khỏi ngắt thì trong main(), sẽ enable các ngắt trở lại.
                              Nhưng cũng có hạn chế bởi nhiều ngắt xảy ra đồng thời, nó sẽ ưu tiên ngắt đưng trước trong bảng vector ngắt, mà nó lại ko theo ý muốn ưu tiên của em. Bởi thế muốn hoàn hảo, thì các ưu tiên ngắt em đặt ra phải phù hợp cùng với trong bảng vector ngắt.

                              Comment


                              • #30
                                +
                                Vâng em xin post cái chương trình của em[code:1]
                                #include <m8c.h> // part specific constants and macros
                                #include "PSoCAPI.h" // PSoC API definitions for all User Modules
                                #include "stdlib.h"

                                char i,tick=1;
                                char disp[4];
                                int count;

                                void send_to_comm(){
                                TX8_1_Start(TX8_1_PARITY_NONE); // Enable UART
                                for(i=0;i<=4;i++){
                                TX8_1_PutChar(disp[i]);
                                while((TX8_1_CONTROL_REG & TX8_1_TX_COMPLETE) == 0);
                                }
                                TX8_1_Stop();
                                }

                                void main()
                                {
                                M8C_EnableGInt; //enable global
                                INT_MSK0 |= INT_MSK0_GPIO;

                                while(1)
                                {
                                while(tick == 1);

                                }
                                }

                                #pragma interrupt_handler PSoC_GPIO_ISR
                                void PSoC_GPIO_ISR()
                                {
                                Counter16_1_Start();
                                //tick =2;
                                while((PRT0DR & 0x01));

                                count = 5000 - Counter16_1_wReadCounter();
                                if((PRT0DR & 0x04)) direct = 1;
                                else direct = 0;
                                Counter16_1_Stop();
                                Counter16_1_WritePeriod (5000);

                                Counter16_2_Start(); // cai này chỉ để nối ra 1 led chỉ thị xem ngắt đã xảy ra chưa

                                itoa(disp,count,10);
                                send_to_comm();
                                }
                                [/code:1]
                                ngoài ra thì trong file boot.asm em đã đổi thành
                                ljmp _PSoC_GPIO_ISR
                                còn khi chọn mode ngắt thì em đã chọn rising edge.

                                Quên chưa nói là em dùng chân P0.0 để đưa vào chân enable của counter nhưng cái chân này nó chỉ cho drive là High Z thôi. Không biết đấy có phải là nguyên nhân không vì em chưa cấp tín hiệu cho chân này thì ngắt đã xảy ra rồi led chỉ thị nháy loạn lên. Mong các cao thủ giúp cho.

                                Comment

                                Về tác giả

                                Collapse

                                OSPF Tìm hiểu thêm về OSPF

                                Bài viết mới nhất

                                Collapse

                                Đang tải...
                                X