Chương trình MSP430 chỉ hoạt động trong chế độ gỡ lỗi


7

Tôi đang cố gắng truy xuất các giá trị từ ADC trên MSP430F5529 của mình và gửi chúng đến máy tính của tôi qua USB, nhưng tôi đang bắt đầu nhỏ. Tất cả những gì tôi có ngay bây giờ là thứ gì đó lấy giá trị ADC và lưu trữ nó trong ADCResults, nếu giá trị đọc vượt quá một nửa Vcc thì đèn LED sẽ bật.

Tôi có chân 6.0 được nối với một cảm biến lực để tôi có thể thấy nó tắt và bật khi tôi đặt ngón tay xuống hoặc thả nó ra.

Chương trình hoạt động hoàn hảo khi tôi chạy nó ở chế độ gỡ lỗi nhưng khi tôi cố chạy nó ngoài chế độ gỡ lỗi (chỉ cấp nguồn cho bo mạch từ máy tính sau khi mã được tải xuống), không có gì xảy ra khi tôi đặt ngón tay lên cảm biến lực.

Điều cực kỳ kỳ lạ là nếu tôi nhấn giữ lại trong khi đặt ngón tay lên cảm biến lực (đặt ngón tay xuống khiến đèn LED bật) và nhả nút đặt lại, đèn LED vẫn sáng cho đến khi tôi nhấn lại lần nữa bằng ngón tay, Vì vậy, có vẻ như thiết lập lại gây ra một vấn đề nhưng tôi không biết làm thế nào.

Lúc đầu, tôi nghĩ rằng thiết lập lại được kéo lên cao liên tục (hoặc thấp, bất cứ điều gì đặt lại thiết bị), nhưng điều đó không thể đúng bởi vì sau đó chương trình sẽ hoạt động nếu tôi giữ lại, nhưng không được!

Đây là mã của tôi:

#include "driverlib.h"

volatile uint16_t ADCResults = 0;

void main(void)
{
    //Stop Watchdog Timer
    WDT_A_hold(WDT_A_BASE);

    //P6.0 ADC option select
    GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

    GPIO_setAsOutputPin(
        GPIO_PORT_P1,
        GPIO_PIN0
        );

    //Initialize the ADC12_A_A Module
    /*
     * Base address of ADC12_A_A Module
     * Use internal ADC12_A_A bit as sample/hold signal to start conversion
     * USE MODOSC 5MHZ Digital Oscillator as clock source
     * Use default clock divider of 1
     */
    ADC12_A_init(ADC12_A_BASE,
                 ADC12_A_SAMPLEHOLDSOURCE_SC,
                 ADC12_A_CLOCKSOURCE_ADC12OSC,
                 ADC12_A_CLOCKDIVIDER_1);

    ADC12_A_enable(ADC12_A_BASE);

    /*
     * Base address of ADC12_A_A Module
     * For memory buffers 0-7 sample/hold for 64 clock cycles
     * For memory buffers 8-15 sample/hold for 4 clock cycles (default)
     * Disable Multiple Sampling
     */
    ADC12_A_setupSamplingTimer(ADC12_A_BASE,
                               ADC12_A_CYCLEHOLD_64_CYCLES,
                               ADC12_A_CYCLEHOLD_4_CYCLES,
                               ADC12_A_MULTIPLESAMPLESDISABLE);

    //Configure Memory Buffer
    /*
     * Base address of the ADC12_A_A Module
     * Configure memory buffer 0
     * Map input A0 to memory buffer 0
     * Vref+ = AVcc
     * Vr- = AVss
     * Memory buffer 0 is not the end of a sequence
     */
    ADC12_A_configureMemoryParam param = {0};
    param.memoryBufferControlIndex = ADC12_A_MEMORY_0;
    param.inputSourceSelect = ADC12_A_INPUT_A0;
    param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
    param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    ADC12_A_configureMemory(ADC12_A_BASE,&param);

    //Enable memory buffer 0 interrupt
    ADC12_A_clearInterrupt(ADC12_A_BASE,
                           ADC12IFG0);
    ADC12_A_enableInterrupt(ADC12_A_BASE,
                            ADC12IE0);

    while(1)
    {
        //Enable/Start sampling and conversion
        /*
         * Base address of ADC12_A_A Module
         * Start the conversion into memory buffer 0
         * Use the single-channel, single-conversion mode
         */
        ADC12_A_startConversion(ADC12_A_BASE,
                                ADC12_A_MEMORY_0,
                                ADC12_A_SINGLECHANNEL);

        //LPM0, ADC12_A_ISR will force exit
        __bis_SR_register(LPM0_bits + GIE);
        //for Debugger
        __no_operation();
    }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(ADC12_VECTOR)))
#endif
void ADC12_A_ISR(void)
{
    switch(__even_in_range(ADC12IV,34))
    {
    case  0: break;       //Vector  0:  No interrupt
    case  2: break;       //Vector  2:  ADC overflow
    case  4: break;       //Vector  4:  ADC timing overflow
    case  6:              //Vector  6:  ADC12IFG0
        //Is Memory Buffer 0 = A0 > 0.5AVcc?

          ADCResults = ADC12_A_getResults(ADC12_A_BASE,
                                        ADC12_A_MEMORY_0);
        if(ADCResults
           >= 0x7ff)
        {
            //set P1.0
            GPIO_setOutputHighOnPin(
                GPIO_PORT_P1,
                GPIO_PIN0
                );
        }
        else
        {
            //Clear P1.0 LED off
            GPIO_setOutputLowOnPin(
                GPIO_PORT_P1,
                GPIO_PIN0
                );
        }

        //Exit active CPU
        __bic_SR_register_on_exit(LPM0_bits);
    case  8: break;       //Vector  8:  ADC12IFG1
    case 10: break;       //Vector 10:  ADC12IFG2
    case 12: break;       //Vector 12:  ADC12IFG3
    case 14: break;       //Vector 14:  ADC12IFG4
    case 16: break;       //Vector 16:  ADC12IFG5
    case 18: break;       //Vector 18:  ADC12IFG6
    case 20: break;       //Vector 20:  ADC12IFG7
    case 22: break;       //Vector 22:  ADC12IFG8
    case 24: break;       //Vector 24:  ADC12IFG9
    case 26: break;       //Vector 26:  ADC12IFG10
    case 28: break;       //Vector 28:  ADC12IFG11
    case 30: break;       //Vector 30:  ADC12IFG12
    case 32: break;       //Vector 32:  ADC12IFG13
    case 34: break;       //Vector 34:  ADC12IFG14
    default: break;
    }
}

CẬP NHẬT

Tôi đã thử làm chức năng tương tự không sử dụng thư viện trình điều khiển ngoại vi và nó dường như hoạt động hoàn hảo bên ngoài trình gỡ lỗi. Điều này khiến tôi tin rằng có điều gì đó không ổn với Thư viện Trình điều khiển Ngoại vi của Texas.

Đây là mã dường như hoạt động tốt bên ngoài trình gỡ lỗi và không sử dụng Thư viện trình điều khiển ngoại vi.

#include <msp430.h>

int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  ADC12CTL0 = ADC12SHT02 + ADC12ON;         // Sampling time, ADC12 on
  ADC12CTL1 = ADC12SHP;                     // Use sampling timer
  ADC12IE = 0x01;                           // Enable interrupt
  ADC12CTL0 |= ADC12ENC;
  P6SEL |= 0x01;                            // P6.0 ADC option select
  P1DIR |= 0x01;                            // P1.0 output

  while (1)
  {
    ADC12CTL0 |= ADC12SC;                   // Start sampling/conversion

    __bis_SR_register(LPM0_bits + GIE);     // LPM0, ADC12_ISR will force exit
    __no_operation();                       // For debugger
  }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12_ISR (void)
#else
#error Compiler not supported!
#endif
{
  switch(__even_in_range(ADC12IV,34))
  {
  case  0: break;                           // Vector  0:  No interrupt
  case  2: break;                           // Vector  2:  ADC overflow
  case  4: break;                           // Vector  4:  ADC timing overflow
  case  6:                                  // Vector  6:  ADC12IFG0
    if (ADC12MEM0 >= 0x7ff)                 // ADC12MEM = A0 > 0.5AVcc?
      P1OUT |= BIT0;                        // P1.0 = 1
    else
      P1OUT &= ~BIT0;                       // P1.0 = 0

    __bic_SR_register_on_exit(LPM0_bits);   // Exit active CPU
  case  8: break;                           // Vector  8:  ADC12IFG1
  case 10: break;                           // Vector 10:  ADC12IFG2
  case 12: break;                           // Vector 12:  ADC12IFG3
  case 14: break;                           // Vector 14:  ADC12IFG4
  case 16: break;                           // Vector 16:  ADC12IFG5
  case 18: break;                           // Vector 18:  ADC12IFG6
  case 20: break;                           // Vector 20:  ADC12IFG7
  case 22: break;                           // Vector 22:  ADC12IFG8
  case 24: break;                           // Vector 24:  ADC12IFG9
  case 26: break;                           // Vector 26:  ADC12IFG10
  case 28: break;                           // Vector 28:  ADC12IFG11
  case 30: break;                           // Vector 30:  ADC12IFG12
  case 32: break;                           // Vector 32:  ADC12IFG13
  case 34: break;                           // Vector 34:  ADC12IFG14
  default: break; 
  }
}

Bạn đang làm điều này trên LaunchPad hoặc một số bảng TI dev khác? Hay đây là thứ bạn đã thiết kế?
DigitalNinja

1
Tôi không đủ quen thuộc với MSP430, nhưng: Có thể WDT được kích hoạt bằng một bit cấu hình không? Một số uC cho phép bạn buộc WDT, có thể bị mô-đun DBGU ghi đè. Tương tự đối với bất kỳ ngắt (bảo vệ) nào khác, nếu tôi quen thuộc hơn, tôi sẽ kiểm tra mã của bạn, nhưng các ngắt là một nguồn rất phổ biến cho loại hành vi này. (Giống như ngắt tràn phân chia: Không được kích hoạt trong chế độ gỡ lỗi trên nhiều thiết bị, nhưng sẽ bị kích hoạt lực khi không ở chế độ gỡ lỗi).
Asmyldof

@DigitalNinja Có, tôi đang sử dụng Launchpad MSP430F5529 Launchpad
Aaron

@Asmyldof Tôi không chắc chắn nếu WDT đang làm điều đó, mã rõ ràng vô hiệu hóa WDT nhưng tôi vẫn là người mới nên tôi không biết.
Aaron

1
@Aaron Cách bạn mô tả thao tác với nút đặt lại làm cho âm thanh giống như chỉ đơn giản là được giữ trong thiết lập lại. Bạn mang nó ra khỏi thiết lập lại, nó sẽ thấy đầu vào của bạn sau đó nó sẽ quay trở lại trạng thái thiết lập lại khi bạn gỡ bỏ nút nhấn. Nhấn nó xuống một lần nữa mang nó ra và tái kích hoạt đèn LED. Thông thường trình gỡ lỗi sẽ chăm sóc thiết lập lại cho bạn vì nó sử dụng dòng thiết lập lại để lập trình. Bạn đã kiểm tra lại cấu hình nhảy của bạn chưa? Có một nút nhảy để thiết lập lại có nhãn (RST).
DigitalNinja

Câu trả lời:


3

Đôi khi lý do cho hành vi đó là các cài đặt tối ưu hóa khác nhau trong chế độ gỡ lỗi và một số biến mà trình biên dịch cho rằng không cần thiết sau đó được tối ưu hóa ngay lập tức.

Các cách khắc phục cho việc này là thêm các vòng loại "dễ bay hơi" vào các biến đó hoặc tắt tối ưu hóa (hoặc ít nhất là tắt nó đi).

Tôi không biết đây có phải là câu trả lời của bạn không (chủ đề vì TL; DR), nhưng mẩu tin này chắc chắn sẽ xuất hiện như một giải pháp khả thi cho các công cụ tìm kiếm.


volatilevòng loại đã có trong mã đầu tiên, vì vậy mặc dù thường là một vấn đề, trong trường hợp này chứ không phải
Arsenal

@Arsenal - đó là biến anh ta có thể thấy . Có lẽ có một cái gì đó bị chôn vùi trong một thư viện mà anh ta không biết. Đầu tiên vượt qua đối với tôi sẽ là tắt tối ưu hóa. Phải mất mười phút đọc để tìm ra cách, bạn làm điều đó, và sau đó bạn biết.
Scott Seidman

@ScottSeidman Cảm ơn bạn đã gợi ý, tối ưu hóa ngay từ đầu, tôi luôn luôn làm việc với họ để bắt đầu với
Aaron

Thư viện trao mọi quyền truy cập vào phần cứng cho một con trỏ dễ bay hơi mà sau đó bị hủy đăng ký, tôi chưa thấy họ sử dụng bất kỳ biến đáng chú ý nào có thể được tối ưu hóa.
Arsenal

2

Tuyên bố miễn trừ trách nhiệm: Tôi không phải là chuyên gia về MSP430.

Tôi đề nghị sử dụng

ADC12_A_disableConversions()

sau

ADC12_A_setupSamplingTimer() 

Đoạn trích từ MSP430 DriverLib for MSP430F5xx_6xx Devices


void ADC12_A_startConversion (uint16_t baseAddress, uint16_t tartingMemoryBufferIndex, uint8_t convertSequenceModeSelect)

Chức năng này cho phép / bắt đầu quá trình chuyển đổi của ADC. Nếu nguồn tín hiệu mẫu / giữ được chọn trong quá trình khởi tạo là ADC12OSC, thì việc chuyển đổi được bắt đầu ngay lập tức, nếu không, nguồn tín hiệu mẫu / giữ được chọn sẽ bắt đầu chuyển đổi bằng một cạnh tăng của tín hiệu. Hãy ghi nhớ khi chọn các chế độ chuyển đổi, đối với các chế độ tuần tự và / hoặc lặp lại, để tiếp tục quá trình lấy mẫu / giữ và chuyển đổi mà không cần kích hoạt từ nguồn tín hiệu mẫu / giữ, nhiều mẫu phải được bật bằng ADC12_A_setupSamplingTimer ( ) hàm. Lưu ý rằng sau khi hàm này được gọi, ADC12_A_disableConversions () phải được gọi để khởi tạo lại ADC, cấu hình lại điều khiển bộ nhớ đệm, bật / tắt bộ hẹn giờ lấy mẫu hoặc để thay đổi điện áp tham chiếu bên trong.

Lưu ý: Ngoài ra có một vài khóa học trực tuyến miễn phí tốt để học thiết kế hệ thống nhúng. Một trong số họ sử dụng MSP430. Tôi có danh sách một vài trong số họ dưới đây.


Người giới thiệu:


1

Tôi tự hỏi tại sao nó hoạt động ở chế độ gỡ lỗi, đã được một thời gian kể từ khi tôi làm việc với MSP430 và tôi không quen với trình điều khiển. Nhưng:

GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

Chắc chắn đó không phải là chức năng bạn muốn sử dụng để chuyển mã pin này sang đầu vào tương tự hay là nó? Tôi sẽ thử:

GPIO_setAsPeripheralModuleFunctionIntputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

Nhưng như đã thấy trong phần mô tả các chức năng của pin (cảm ơn @CL.), Rõ ràng rằng việc đặt pin cho chức năng ngoại vi thực sự sẽ là đủ và hướng bị bỏ qua. Vì vậy, nó chỉ gây hiểu lầm nhưng không phải là một công cụ thỏa thuận.

Sau đó, có một điều nhỏ param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;có lẽ nên có param.endOfSequence = ADC12_A_ENDOFSEQUENCE;nhưng vì bạn chỉ thực hiện một chuyển đổi kênh duy nhất, điều đó không thành vấn đề (nó chỉ rõ ràng hơn một chút). Và có thể thay đổi ADC12IFG0ADC12IE0thành ADC12_A_IFG0ADC12_A_IE0(nhưng chúng chỉ được định nghĩa cho các giá trị khác, vì vậy không có vấn đề chức năng)

Và bạn đang thiếu một break;trường hợp sau trường hợp của bạn trong bảng vectơ ngắt, nhưng điều đó sẽ không ảnh hưởng đến chương trình nhiều, chỉ là một nguồn cho các lỗi trong tương lai.

Vì vậy, từ góc độ firmware tôi chỉ có nitpicks nhỏ.

Dựa trên các nhận xét và đọc qua bảng errata , khiến tôi tự hỏi liệu một lần duy nhất __no_operation();sau __bic_SR_register_on_exit(LPM0_bits);ISR có giải quyết được vấn đề không. Các lỗi không đề cập rõ ràng trường hợp có ở đây, nhưng có vấn đề liên quan đến việc cài đặt các chế độ năng lượng thấp, thoát khỏi các chế độ năng lượng thấp và làm hỏng bộ đếm chương trình. Vì vậy, có lẽ đó là một trường hợp khác. Những hiệu ứng này có thể không xuất hiện trong quá trình gỡ lỗi vì mô-đun mô phỏng can thiệp vào việc thực thi bình thường của lõi.

Nhưng bạn cũng đã đề cập rằng, nếu bạn xóa ngắt toàn cầu thì chương trình của bạn cũng hoạt động. Điều đó dẫn đến tôi nghĩ rằng chương trình của bạn bị kẹt trong một ngắt nhưng không phải là chương trình ADC. Bạn không phải xóa cờ ngắt của ADC vì điều đó được thực hiện tự động khi đọc bộ nhớ của ADC.

Chỉ cần một lưu ý khác về lập trình, tôi sẽ phân tích giá trị ADC ra khỏi ISR. Giữ chúng càng nhỏ càng tốt, chỉ cần đọc giá trị vào biến toàn cục của bạn và để chế độ năng lượng thấp khi thoát. Làm tất cả những thứ khác trong ứng dụng chính của bạn. Có những trường hợp bạn sẽ cần độ trễ gián đoạn ngắn nhất có thể và nếu bạn thực hiện công cụ bên trong ISR, bạn sẽ chặn các ngắt khác (ngoại trừ bạn kích hoạt các ngắt lồng nhau, nhưng chúng cũng rất tệ).


Như bảng trên trang tiếp theo hiển thị, cấu hình pin cho chức năng mô-đun (P6SEL.0 = 1) là đủ; hướng đi không quan trọng.
CL.

Cảm ơn các mẹo, @Arsenal tôi nghĩ rằng tôi đã thu hẹp các triệu chứng, nhưng không chắc chắn nguyên nhân là gì. Có vẻ như nó chỉ đọc ADC một lần trực tiếp sau khi thiết lập lại
Aaron

@Arsenal Bây giờ tôi biết vấn đề phải làm với sự chậm trễ và các chức năng nội tại, nhưng tôi không biết đủ về các chức năng nội tại để khắc phục nó
Aaron

@Aaron Tôi đã thay đổi câu trả lời của mình, có lẽ nó giúp được một chút, để giải trí, tôi cũng đã thêm một số hướng dẫn chung cho ISR.
Arsenal

@Arsenal cảm ơn bạn, tôi đã xem xét nó. Tôi vẫn đang thử những điều mới và điều đó có thể là một bước đột phá nếu bạn muốn xem OP cập nhật của tôi
Aaron
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.