2013-12-17 6 views
4

dsPIC33FJ128GP802 마이크로 컨트롤러가있는 MPLAB X 1.70 사용.다양한 크기의 어레이를위한 UART DMA

다른 샘플링 속도 (하나는 50Hz, 다른 하나는 1000Hz)로 두 센서에서 데이터를 수집하는 응용 프로그램이 있는데 두 센서 패킷도 서로 다른 크기입니다 (하나는 5 바이트이고 다른 하나는 21 바이트입니다)). 아래와 같이 지금까지 내가 수동 UART의 transmision을 사용했습니다까지 :

void UART_send(char *txbuf, char size) { 
    // Loop variable. 
    char i; 

    // Loop through the size of the buffer until all data is sent. The while 
    // loop inside checks for the buffer to be clear. 
    for (i = 0; i < size; i++) { 
     while (U1STAbits.UTXBF); 
     U1TXREG = *txbuf++; 
    } 
} 

변화하는 크기의 배열 (5 또는 21 바이트) 각 바이트를 통해 루프 크기와 루프에 대한 간단한으로,이 함수에 보내졌다 UART tx 레지스터 U1TXREG를 통해 출력한다.

이제 많은 양의 데이터를 전송할 때 시스템에 대한 압력을 완화하기 위해 DMA를 구현하려고합니다. 내 UART 수신 및 ADC에 DMA를 사용했지만 전송에 문제가 있습니다. 나는 핑퐁 모드를 켜고 끄고, 원샷과 연속 모드를 시도했지만, 21 바이트 패킷을 보낼 때마다 이상한 값과 제로 값 패딩으로 망가 뜨린다.

아래와 같이 DMA를 초기화하고 있습니다.

void UART_TX_DMA_init() { 

     DMA2CONbits.SIZE = 0;         // 0: word; 1: byte 
     DMA2CONbits.DIR = 1;         // 0: uart to device; 1: device to uart 
     DMA2CONbits.AMODE = 0b00; 
     DMA2CONbits.MODE = 1;         // 0: contin, no ping pong; 1: oneshot, no ping pong; 2: contin, ping pong; 3: oneshot, ping pong. 

     DMA2PAD = (volatile unsigned int) &U1TXREG; 

     DMA2REQ = 12;     // Select UART1 Transmitter 

     IFS1bits.DMA2IF = 0;   // Clear DMA Interrupt Flag 
     IEC1bits.DMA2IE = 1;   // Enable DMA interrupt 
} 

DMA 인터럽트 플래그를 지우고 있습니다. DMA 배열을 만들기 위해 다음과 같은 함수가 있습니다.

char TXBufferADC[5] __attribute__((space(dma))); 
char TXBufferIMU[21] __attribute__((space(dma))); 

void UART_send(char *txbuf, char size) { 

    // Loop variable. 
    int i; 

    DMA2CNT = size - 1; // x DMA requests 

    if (size == ADCPACKETSIZE) { 
     DMA2STA = __builtin_dmaoffset(TXBufferADC); 
     for (i = 0; i < size; i++) { 
      TXBufferADC[i] = *txbuf++; 
     } 
    } else if (size == IMUPACKETSIZE) { 
     DMA2STA = __builtin_dmaoffset(TXBufferIMU); 
     for (i = 0; i < size; i++) { 
      TXBufferIMU[i] = *txbuf++; 
     } 
    } else { 
     NOTIFICATIONLED ^= 1; 
    } 

    DMA2CONbits.CHEN = 1; // Re-enable DMA2 Channel 
    DMA2REQbits.FORCE = 1; // Manual mode: Kick-start the first transfer 
} 

이 예제는 탁구가 꺼진 상태입니다. 동일한 DMA2STA 레지스터를 사용하고 있는데 어떤 패킷 유형을 가지고 있는지에 따라 배열을 변경합니다. 전송할 데이터에서 패킷 유형을 결정하고 전송할 DMA 바이트 (DMA2CNT)를 변경하고 for 루프로 이전과 동일한 배열을 만든 다음 채널을 다시 활성화하여 첫 번째 전송을 수행합니다.

큰 데이터 패킷에 대한 데이터를 처리하는 데 훨씬 오래 걸리고 DMA에 이러한 패킷이 누락되어 있고 그 자리에 널 패킷이 전송된다고 생각하기 시작합니다. 버퍼를 만들고 첫 번째 전송을 강제하기 전에 폴링중인 것 같습니다. 아마도 모든 여론 조사에 힘이 필요한 것은 아닙니다. 나는 모른다 ...

도움이 될 것입니다.

+0

'UART_send()'중에 인터럽트를 비활성화하지 않아도 인터럽트가 발생하지 않도록 할 필요가 없습니까? – chux

+0

좋은 제안, 내일 다시 시도해 보겠습니다. 감사합니다. DMA의 요점을 부정하지 않겠습니까? 고의적으로 DMA 인터럽트를 일시 중지했다면 수동 UART 방법만큼 빠르지 않습니까? – ritchie888

+0

아마 "내가 UART_send()에서 인터럽트를 비활성화하지 않아도 인터럽트가 처리되는 것을 막을 수 있습니까?"라고 말했어야합니다. " 루틴에서 _cause_ 인터럽트를 실행해도 문제가 없지만 루틴은 원자 적이어야하고 중간에 끼어 들지 않도록 잠겨져 있어야합니다. 'UART_send()'에서 인터럽트 _handling_을 일시 중지하는 것이 좋습니다. – chux

답변

1

며칠 후에이 문제를 해결했다고 생각합니다.

내가 겪은 주요 문제는 DMA 인터럽트가 이전 전송보다 빠르게 폴링된다는 것이었고, 따라서 다음 패키지가 이전 패키지를 덮어 쓰기 전에 패키지 세그먼트 만 얻고있었습니다. 이것은 단순히 UART 전송의 끝을 기다리면서 해결되었습니다 :

while (! U1STAbits.TRMT);

원래 데이터 배열을 DMA가 인식하는 배열로 간단히 지정하여 패키지 데이터로 새로운 DMA를 다시 만드는 중복성을 피할 수있었습니다. 결국

프로세스가 거의 최소이며, 패키지가 생성 될 때마다 호출 된 함수는 다음과 관계없이 패키지의 크기가 상기 DMA는 그것이 DMA2CNT을 이용하여 전송 용량을 변경하는 것에

void sendData() { 
    // Check that last transmission has completed. 
    while (!U1STAbits.TRMT); 

    DMA2CNT = bufferSize - 1; 

    DMA2STA = __builtin_dmaoffset(data); 

    DMA2CONbits.CHEN = 1; // Re-enable DMA0 Channel 
    DMA2REQbits.FORCE = 1; // Manual mode: Kick-start the first transfer 
} 

등록을하면 간단히 DMA를 다시 활성화하고 첫 번째 비트를 강제 실행합니다.는 DMA 설정

했다 :

DMA2CONbits.SIZE = 1; 
DMA2CONbits.DIR = 1; 
DMA2CONbits.AMODE = 0b00; 
DMA2CONbits.MODE = 1; 

DMA2PAD = (volatile unsigned int) &U1TXREG; 

DMA2REQ = 12;        // Select UART1 Transmitter 

IFS1bits.DMA2IF = 0;      // Clear DMA Interrupt Flag 
IEC1bits.DMA2IE = 1;      // Enable DMA interrupt 

원샷, 아니 탁구, 바이트 전송, UART1 TX에 대한 모든 올바른 매개 변수된다.

앞으로 도움이되기를 바랍니다. 일반 원칙은 대부분의 PIC 마이크로 컨트롤러에 적용될 수 있습니다.