天天看點

高通平台序列槽調試 AP與子產品序列槽通訊調試總結

1:檢查AP端序列槽配置是否ok:

a:高通平台檢視DMA傳輸:

echo 1 > /sys/kernel/debug/msm_serial_hsl/loopback.0 //打開回環開關

adb shell cat /dev/ttyHSL1

另起視窗

# adb shell

# echo 11111111 > /dev/ttyHSL1

若DMA通道ok,控制台會循環顯示;

b:檢視uart gpio是否ok:

tx高電平、rfr為低電平,rx,cts為輸入;       

如果tx為低電平,那麼gpio肯定沒有配置好,再次檢查gpio配置問題;

如果以上2步都ok,那麼UART應該ok了,再次檢查:

adb shell cat /dev/ttyHSL1

将TX與RX短接;

另起視窗

# adb shell

# echo 11111111 > /dev/ttyHSL1

循環顯示那麼恭喜UART功能配置好了。

2:Termios參數配置:

高通平台序列槽調試 AP與子產品序列槽通訊調試總結

影響通訊資料格式的關鍵

幾個參數:

1:波特率-speed,通常

115200,最高4M;

2:奇偶校驗-Parity,通

常為None;

3:資料位-Data,通常

8bit;

4:停止位-Stopbits,通

常1bit;

一般情況下預設為115200 8N1,也就是波特率115200,8bit資料位,無奇偶校驗,1bit停止位。

為了使得AP可以與子產品序列槽通訊,必須先了解子產品的termios設定。

Ap端termios設定:

首先應用打開序列槽時會設定termios:

termios.c_cflag &= ~CSIZE;
termios.c_cflag |= CS8;
termios.c_cflag &= ~CSTOPB;
termios.c_cflag &= ~PARENB;
termios.c_cflag &= ~CBAUD;
termios.c_cflag |= B3000000; 
termios.c_cflag |= CREAD | CLOCAL;
termios.c_cflag |= CRTSCTS; /* turn on hardware flow control */
termios.c_iflag &= ~(IXOFF | IXON | IXANY); /* soft flow control */
           

驅動接口會根據termios參數來設定底層序列槽:

以8064 msm_seriel_hs.c為例說明:

uart接口封裝:

static struct uart_ops msm_hs_ops = {
.tx_empty = msm_hs_tx_empty,
.set_mctrl = msm_hs_set_mctrl_locked,
.get_mctrl = msm_hs_get_mctrl_locked,
.stop_tx = msm_hs_stop_tx_locked,
.start_tx = msm_hs_start_tx_locked,
.stop_rx = msm_hs_stop_rx_locked,
.enable_ms = msm_hs_enable_ms_locked,
.break_ctl = msm_hs_break_ctl,
.startup = msm_hs_startup,
.shutdown = msm_hs_shutdown,
.set_termios = msm_hs_set_termios,
.type = msm_hs_type,
.config_port = msm_hs_config_port,
.release_port = msm_hs_release_port,
.request_port = msm_hs_request_port,
.flush_buffer = msm_hs_flush_buffer_locked,
};
           

下面是底層設定函數,上層打開序列槽,參數未固定的話驅動走的是8N1,底層調試隻使用echo或者cat /dev/ttyHSL0時

波特率一律是9600,子產品不是9600時那麼通訊肯定會失敗,是以AP需要根據子產品重新設定。

波特率。

//設定termios接口

/*
* termios : new ktermios
* oldtermios: old ktermios previous setting
*
* Configure the serial port
*/
static void msm_hs_set_termios(struct uart_port *uport,
struct ktermios *termios,
struct ktermios *oldtermios)
{
unsigned int bps;
unsigned long data;
unsigned long flags;
int ret;
unsigned int c_cflag = termios->c_cflag;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
mutex_lock(&msm_uport->clk_mutex);
spin_lock_irqsave(&uport->lock, flags);
/*
* Disable Rx channel of UARTDM
* DMA Rx Stall happens if enqueue and flush of Rx command happens
* concurrently. Hence before changing the baud rate/protocol
* configuration and sending flush command to ADM, disable the Rx
* channel of UARTDM.
* Note: should not reset the receiver here immediately as it is not
* suggested to do disable/reset or reset/disable at the same time.
*/
data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
data &= ~UARTDM_RX_DM_EN_BMSK;
msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
/* 300 is the minimum baud support by the driver */
bps = uart_get_baud_rate(uport, termios, oldtermios, 200, 4000000);
/* Temporary remapping 200 BAUD to 3.2 mbps */
if (bps == 200)
bps = 3200000;
uport->uartclk = clk_get_rate(msm_uport->clk);
if (!uport->uartclk)
msm_hs_set_std_bps_locked(uport, bps);
else
flags = msm_hs_set_bps_locked(uport, bps, flags);//函數裡面設定baud;
data = msm_hs_read(uport, UARTDM_MR2_ADDR);
data &= ~UARTDM_MR2_PARITY_MODE_BMSK;
/* set parity */ //設定奇偶校驗
if (PARENB == (c_cflag & PARENB)) {
if (PARODD == (c_cflag & PARODD)) {
data |= ODD_PARITY;
} else if (CMSPAR == (c_cflag & CMSPAR)) {
data |= SPACE_PARITY;
} else {
data |= EVEN_PARITY;
}
}
/* Set bits per char */       //設定資料位
data &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK;
switch (c_cflag & CSIZE) {
case CS5:
data |= FIVE_BPC;
break;
case CS6:
data |= SIX_BPC;
break;
case CS7:
data |= SEVEN_BPC;
break;
default:
data |= EIGHT_BPC;
break;
}
/* stop bits */ //設定停止位
if (c_cflag & CSTOPB) {
data |= STOP_BIT_TWO;
} else {
/* otherwise 1 stop bit */
data |= STOP_BIT_ONE;
}
data |= UARTDM_MR2_ERROR_MODE_BMSK;
/* write parity/bits per char/stop bit configuration */
msm_hs_write(uport, UARTDM_MR2_ADDR, data);
/* Configure HW flow control */ //設定是否使用硬體流控
data = msm_hs_read(uport, UARTDM_MR1_ADDR);
data &= ~(UARTDM_MR1_CTS_CTL_BMSK |
UARTDM_MR1_RX_RDY_CTL_BMSK);
if (c_cflag & CRTSCTS) {
data |= UARTDM_MR1_CTS_CTL_BMSK;
data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
}
msm_hs_write(uport, UARTDM_MR1_ADDR, data);
uport->ignore_status_mask = termios->c_iflag & INPCK;
uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
uport->ignore_status_mask |= termios->c_iflag & IGNBRK;
uport->read_status_mask = (termios->c_cflag & CREAD);
msm_hs_write(uport, UARTDM_IMR_ADDR, 0);
/* Set Transmit software time out */
uart_update_timeout(uport, c_cflag, bps);
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
if (msm_uport->rx.flush == FLUSH_NONE) {
wake_lock(&msm_uport->rx.wake_lock);
msm_uport->rx.flush = FLUSH_IGNORE;
/*
* Before using dmov APIs make sure that
* previous writel are completed. Hence
* dsb requires here.
*/
mb();
msm_uport->rx_discard_flush_issued = true;
/* do discard flush */
msm_dmov_flush(msm_uport->dma_rx_channel, 0);
spin_unlock_irqrestore(&uport->lock, flags);
pr_debug("%s(): wainting for flush completion.\n",
__func__);
ret = wait_event_timeout(msm_uport->rx.wait,
msm_uport->rx_discard_flush_issued == false,
RX_FLUSH_COMPLETE_TIMEOUT);
if (!ret)
pr_err("%s(): Discard flush completion pending.\n",
__func__);
spin_lock_irqsave(&uport->lock, flags);
}
msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
mb();
spin_unlock_irqrestore(&uport->lock, flags);
mutex_unlock(&msm_uport->clk_mutex);
}
           

3:序列槽通訊問題總結:

遇見過子產品不能響應AP的問題:

1:硬體流控問題,若子產品使用了硬體流控,配置rfr與cts,使得子產品認為

AP準備好了,可以發送資料了。

2:AP端波特率沒有與子產品比對上,要是懷疑AP波特率設定是否ok,可以将序列槽線連接配接TX,

設定termios 波特率來看輸出是否ok,這種方法還可以測試驗證AP端各個波特率是否OK,我使用的

minicon可以驗證到460800。

繼續閱讀