2011-07-06 25 views
8

Tôi đang truyền dữ liệu từ vi điều khiển PIC24H của tôi qua 460Kbaud UART sang mô-đun vô tuyến bluetooth. Trong hầu hết các điều kiện, dòng này hoạt động tốt và mô-đun bluetooth sử dụng các dòng CTS và RTS để quản lý kiểm soát luồng khi bộ đệm dữ liệu nội bộ của nó đầy. Tuy nhiên, có một loại lỗi trong mô-đun bluetooth đặt lại khi dữ liệu được liên tục gửi đến nó mà không bị gián đoạn, điều này xảy ra nếu dữ liệu của tôi được sao lưu trong một nút cổ chai khác.Làm thế nào để tăng tốc truyền dẫn UART gián đoạn PIC24H?

Sẽ tốt hơn nếu mô-đun hoạt động bình thường, nhưng đó là ngoài tầm kiểm soát của tôi. Vì vậy, có vẻ như lựa chọn duy nhất của tôi là làm một số dữ liệu điều chỉnh về phía tôi để đảm bảo rằng tôi không vượt quá giới hạn thông lượng dữ liệu (mà tôi biết gần bằng thử nghiệm).

Câu hỏi của tôi là cách triển khai điều chỉnh tốc độ dữ liệu?

Triển khai UART hiện tại của tôi là bộ đệm FIFO RAM tròn dài 1024 byte mà vòng lặp chính ghi dữ liệu vào. Một ngắt ngoại vi được kích hoạt bởi PIC khi byte cuối cùng đã được gửi ra bởi phần cứng UART và ISR của tôi đọc byte tiếp theo từ bộ đệm và gửi nó đến phần cứng UART.

Dưới đây là một ý tưởng về mã nguồn:

uart_isr.c

//*************** Interrupt Service routine for UART2 Transmission 
void __attribute__ ((interrupt,no_auto_psv)) _U2TXInterrupt(void) 
{  
//the UART2 Tx Buffer is empty (!UART_TX_BUF_FULL()), fill it 
//Only if data exists in data buffer (!isTxBufEmpty()) 
while(!isTxBufEmpty()&& !UART_TX_BUF_FULL()) { 
    if(BT_CONNECTED) 
    { //Transmit next byte of data 
     U2TXREG = 0xFF & (unsigned int)txbuf[txReadPtr]; 
     txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE; 
    }else{ 
     break; 
    } 
} 
IFS1bits.U2TXIF = 0; 
} 

uart_methods.c

//return false if buffer overrun 
BOOL writeStrUART(WORD length, BYTE* writePtr) 
{ 
    BOOL overrun = TRUE; 
    while(length) 
    { 
     txbuf[txWritePtr] = *(writePtr); 
     //increment writePtr 
     txWritePtr = (txWritePtr + 1) % TX_BUFFER_SIZE; 
     if(txWritePtr == txReadPtr) 
     { 
      //write pointer has caught up to read, increment read ptr 
      txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE; 
      //Set overrun flag to FALSE 
      overrun = FALSE; 
     } 

     writePtr++; 
     length--; 
    } 

    //Make sure that Data is being transmitted 
    ensureTxCycleStarted(); 

    return overrun; 
} 


void ensureTxCycleStarted() 
{ 
    WORD oldPtr = 0; 
    if(IS_UART_TX_IDLE() && !isTxBufEmpty()) 
    { 
     //write one byte to start UART transmit cycle 
     oldPtr = txReadPtr; 
     txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE;//Preincrement pointer 
     //Note: if pointer is incremented after U2TXREG write, 
     //  the interrupt will trigger before the increment 
     //  and the first piece of data will be retransmitted. 
     U2TXREG = 0xFF & (unsigned int)txbuf[oldPtr]; 
    } 
} 

Sửa
Có hai cách mà throttling thể được thực hiện như tôi thấy:

  1. Thực thi một khoảng thời gian trễ giữa byte UART được viết để đặt giới hạn trên về thông lượng dữ liệu.

  2. Giữ số đếm byte được truyền qua một khung thời gian nhất định và nếu vượt quá số byte tối đa cho khoảng thời gian đó tạo ra độ trễ lâu hơn một chút trước khi tiếp tục truyền.

Hoặc là tùy chọn về mặt lý thuyết sẽ hoạt động, việc triển khai của tôi sẽ tự hỏi.

+0

Mô tả loại "ngắt" nào mà mô-đun yêu cầu hoạt động ... –

+0

@Ben Jackson sẽ rất tuyệt nếu tôi biết. Đó là một lỗi không phải là một tính năng để nó không được ghi lại. Về cơ bản nó reset sau khoảng 3 giây thông lượng không đổi, mặc dù nó được điều khiển luồng. Tôi có thể lấy đi khoảng 25kbps thông lượng trung bình. – CodeFusionMobile

Trả lời

2

Có thể cách tiếp cận hạn ngạch là những gì bạn muốn. Sử dụng ngắt định kỳ khoảng thời gian có liên quan, thêm hạn ngạch "byte được truyền" vào biến toàn cầu đến một điểm mà bạn không đi qua một số mức điều chỉnh cho sự cố định có liên quan. Sau đó, chỉ cần kiểm tra nếu có hạn ngạch trước khi bạn đến để gửi một byte. Trong quá trình truyền mới, sẽ có một nơi ẩn náu ban đầu nhưng sau đó hạn ngạch sẽ giới hạn tốc độ truyền tải.

~~some periodic interrupt 
if(bytes_to_send < MAX_LEVEL){ 
    bytes_to_send = bytes_to_send + BYTES_PER_PERIOD; 
    } 
~~in uart_send_byte 
if(bytes_to_send){ 
    bytes_to_send = bytes_to_send - 1; 
    //then send the byte 
+0

Tôi thích phương pháp này. Vẫn gửi khối dữ liệu, nhưng cho phép quản lý luồng mà không trì hoãn từng byte – CodeFusionMobile

2

Nếu bạn có bộ hẹn giờ miễn phí hoặc nếu bạn có thể sử dụng bộ tính giờ hiện tại, bạn có thể thực hiện một số loại "lỗi" của các byte được gửi.

Hãy tưởng tượng bạn có var toàn cục này, byte_interval và bạn có bộ hẹn giờ tràn (và kích hoạt ISR) sau mỗi micro giây. Sau đó, nó có thể trông giống như thế này:

timer_usec_isr() { 
    // other stuff 
    if (byte_interval) 
     byte_interval--; 
} 

Và sau đó trong chức năng "putchar", bạn có thể có một cái gì đó như:

uart_send_byte(unsigned char b) { 
    if (!byte_interval) { // this could be a while too, 
          // depends on how you want to structure the code 
     //code to send the byte 
     byte_interval = AMOUNT_OF_USECS; 
    } 

} 

Tôi xin lỗi để không nhìn nhiều vào mã của bạn vì vậy tôi có thể cụ thể hơn. Đây chỉ là một ý tưởng, tôi không biết nếu nó phù hợp với bạn.

+0

Tôi không muốn đặt một sự chậm trễ giữa mỗi byte, vì điều đó sẽ yêu cầu khởi động lại thường xuyên chu kỳ tx. Có cách nào tôi có thể thích ứng với điều này để phát hiện khi x số lượng (quá nhiều) byte đã được truyền trong usecs y cuối cùng và kích hoạt một sự chậm trễ hẹn giờ? Điều đó sẽ phù hợp với cấu trúc mã của tôi tốt hơn một chút. – CodeFusionMobile

+0

Bạn có thể yêu cầu UART đặt txdone ngay cả khi không có nhân vật thực sự không? Nếu bạn có thể, thì nó sẽ gửi bit dừng nếu nó không truyền dữ liệu thực. Sau đó, bạn chỉ có thể loại bỏ 2 hoặc 3 txints mỗi 1024 (nói) ký tự và nhận lại sau 2 hoặc 3 lần ký tự trôi đi. Nếu bạn có thể làm việc đó, đó là những gì tôi sẽ cố gắng đầu tiên. –

+0

@Pete Wilson Tôi không thể thiết lập txdone mà không bắt đầu một chu trình truyền dẫn mà sẽ đẩy ra dữ liệu trống. Tôi phải làm một sự chậm trễ bộ đếm thời gian hoặc một cái gì đó để kích hoạt ngắt. – CodeFusionMobile

1

Đầu tiên, có hai loại điều khiển luồng nối tiếp được sử dụng phổ biến.

Bạn nói CTS được bật, nhưng bạn có thể muốn xem nếu XON/XOFF thể được kích hoạt một cách nào đó.

Một cách tiếp cận khác nếu bạn có thể cấu hình nó chỉ đơn giản là sử dụng tốc độ truyền thấp hơn. Điều này rõ ràng phụ thuộc vào những gì bạn có thể cấu hình ở đầu bên kia của liên kết, nhưng nó thường là cách dễ nhất để khắc phục sự cố khi các thiết bị không thể đối phó với việc truyền tốc độ cao hơn.

+0

Điều khiển luồng phần cứng được bật và được điều khiển bởi mô-đun bluetooth. Tôi đã thử thực hiện một cài đặt tốc độ truyền thấp hơn, nhưng điều đó gây ra quá nhiều vấn đề khác (mặc dù nó đã khắc phục vấn đề cụ thể này một cách hoàn hảo). 1 cho câu trả lời tốt với dữ liệu được đưa ra mặc dù. – CodeFusionMobile

+0

Như một lưu ý phụ, các vấn đề khác xuất phát từ thực tế là tôi có hai tốc độ dữ liệu được cấu hình thời gian chạy, và để chuyển đổi tốc độ truyền, tôi phải cấu hình mô-đun BT và sau đó đặt lại nó, một quá trình 2 giây, để kết nối lại sau đó. Vì vậy, giảm tốc độ truyền chỉ không hoạt động từ quan điểm cụ thể của ứng dụng. – CodeFusionMobile

1

cách tiếp cận hẹn giờ mà thêm chậm trễ đến Tx tại thời điểm cụ thể:

  • Configure một chạy timer miễn phí với tốc độ định kỳ thích hợp. Trong ISR hẹn giờ, chuyển đổi một chút trong biến trạng thái toàn cục (delayBit)
  • Trong ISR UART, nếu delayBit ​​cao và delayPostedBit thấp, sau đó thoát khỏi TX ISR mà không xóa cờ ngắt TX và đặt bit trong biến trạng thái toàn cục (delayPostedBit). Nếu delayBit ​​thấp, thì hãy xóa delayPostedBit. Kết quả là gây ra độ trễ bằng một thời gian chờ của lịch ISR, vì ISR sẽ được nhập lại. Đây không phải là một sự chậm trễ chờ đợi vì vậy sẽ không ảnh hưởng đến thời gian của phần còn lại của hệ thống.
  • Điều chỉnh khoảng thời gian để thêm thời gian chờ vào các khoảng thời gian thích hợp.
+0

Thoát khỏi TX ISR mà không xóa kết quả cờ ngắt trong ISR khóa CPU với các lần nhớ liên tục, do đó chặn vòng lặp chính, không được chấp nhận cho ứng dụng của tôi . – CodeFusionMobile

+0

Nó sẽ thoát ISR trên lần lặp thứ hai thông qua ISR. Đó là ý định (thêm độ trễ bằng 1 độ trễ ISR), điều này sẽ cho phép thời gian hạt mịn nhất được cho phép. Tôi giả định độ trễ mong muốn là tính bằng micro giây, không phải là mili giây. –

Các vấn đề liên quan