📄 ssp.c
字号:
/******************** (C) COPYRIGHT 2010 Embest Info&Tech Co.,LTD. ************
* 文件名: ssp.c
* 作者 : Wuhan R&D Center, Embest
* 日期 : 01/18/2010
* 描述 : NXP LPC11xx 系列处理器 SSP API 文件.
*******************************************************************************
*******************************************************************************
* 历史:
* 01/18/2010 : V1.0 初始版本
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "LPC11xx.h" /* LPC11xx 外设寄存器 */
#include "gpio.h"
#include "ssp.h"
/* 所有寄存器的数据 */
volatile uint32_t interruptRxStat0 = 0;
volatile uint32_t interruptOverRunStat0 = 0;
volatile uint32_t interruptRxTimeoutStat0 = 0;
volatile uint32_t interruptRxStat1 = 0;
volatile uint32_t interruptOverRunStat1 = 0;
volatile uint32_t interruptRxTimeoutStat1 = 0;
/**
* 函数名: SSP0_IRQHandler
* 描述 : SSP 端口用做 SPI 通信.
* SSP 中断处理程序
* 算法是,如果 RXFIFO 至少半满,开始接收直到为空。
* 如果 TXFIFO 至少半空,开始发送知道为满。
* 这样可以最大限度的使用 FIFOs 。
*
* 参数: 无
* 返回值: 无
*/
void SSP0_IRQHandler(void)
{
uint32_t regValue;
regValue = LPC_SSP0->MIS;
/* 接收溢出中断 */
if ( regValue & SSPMIS_RORMIS )
{
interruptOverRunStat0++;
/* 清除中断 */
LPC_SSP0->ICR = SSPICR_RORIC;
}
/* 接收超时中断 */
if ( regValue & SSPMIS_RTMIS )
{
interruptRxTimeoutStat0++;
/* 清除中断 */
LPC_SSP0->ICR = SSPICR_RTIC;
}
/* 请注意,在 main 和 ISR, CurrentRxIndex 和 CurrentTxIndex
作为全局变量共享。 这可能造成一些竞争条件使 main 和 ISR 同时
操纵这些变量。 SSPSR_BSY 检查 (polling) main 和 ISR 能够防止
这样的竞争情况出现 */
/* Rx 至少半满 */
if ( regValue & SSPMIS_RXMIS )
{
/* 接收直到为空 */
interruptRxStat0++;
}
return;
}
/**
* 函数名: SSP1_IRQHandler
* 描述 : SSP 端口用做 SPI 通信.
* SSP 中断处理程序
* 算法是,如果 RXFIFO 至少半满,开始接收直到为空。
* 如果 TXFIFO 至少半空,开始发送知道为满。
* 这样可以最大限度的使用 FIFOs 。
*
* 参数: 无
* 返回值: 无
*/
void SSP1_IRQHandler(void)
{
uint32_t regValue;
regValue = LPC_SSP1->MIS;
/* 接收溢出中断 */
if ( regValue & SSPMIS_RORMIS )
{
interruptOverRunStat1++;
/* 清除中断 */
LPC_SSP1->ICR = SSPICR_RORIC;
}
/* 接收超时中断 */
if ( regValue & SSPMIS_RTMIS )
{
interruptRxTimeoutStat1++;
LPC_SSP1->ICR = SSPICR_RTIC; /* clear interrupt */
}
/* 请注意,在 main 和 ISR, CurrentRxIndex 和 CurrentTxIndex
作为全局变量共享。 这可能造成一些竞争条件使 main 和 ISR 同时
操纵这些变量。 SSPSR_BSY 检查 (polling) main 和 ISR 能够防止
这样的竞争情况出现 */
/* Rx 至少半满 */
if ( regValue & SSPMIS_RXMIS )
{
/* 接收直到为空 */
interruptRxStat1++;
}
return;
}
/**
* 函数名: SSP_IOConfig
* 描述: SSP 初始化
* 参数: 无
* 返回值: 无
*/
void SSP_IOConfig( uint8_t portNum )
{
if ( portNum == 0 )
{
LPC_SYSCON->PRESETCTRL |= (0x1<<0);
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11);
/* 除以 2 */
LPC_SYSCON->SSP0CLKDIV = 0x02;
/* SSP I/O 配置 */
LPC_IOCON->PIO0_8 &= ~0x07;
LPC_IOCON->PIO0_8 |= 0x01; /* SSP MISO */
LPC_IOCON->PIO0_9 &= ~0x07;
LPC_IOCON->PIO0_9 |= 0x01; /* SSP MOSI */
#ifdef __JTAG_DISABLED
LPC_IOCON->SCKLOC = 0x00;
LPC_IOCON->JTAG_TCK_PIO0_10 &= ~0x07;
LPC_IOCON->JTAG_TCK_PIO0_10 |= 0x02; /* SSP CLK */
#else
#if 1
/* 在 HummingBird 1(HB1), SSP CLK 可以被重定向到不同的引脚,
而不像 JTAG TCK, 可以是 P2.11 func. 1 或 P0.6 func. 2. */
LPC_IOCON->SCK_LOC = 0x01;
LPC_IOCON->PIO2_11 = 0x01; /* P2.11 功能 1 是 SSP 时钟, 需要
同时设置 IOCONSCKLOC 寄存器 */
#else
LPC_IOCON->SCK_LOC = 0x02;
LPC_IOCON->PIO0_6 = 0x02; /* P0.6 功能 2 是 SSP 时钟, 需要
同时设置 IOCONSCKLOC 寄存器 */
#endif
#endif /* endif __JTAG_DISABLED */
#if USE_CS
LPC_IOCON->PIO0_2 &= ~0x07;
LPC_IOCON->PIO0_2 |= 0x01; /* SSP SSEL */
#else
/* 使能 AHB 到 GPIO 时钟 */
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
/* SSP SSEL 是 GPIO 引脚 */
LPC_IOCON->PIO0_2 &= ~0x07;
/* port0, 第 2 位设置为 GPIO 输出并为高 */
GPIOSetDir( PORT0, 2, 1 );
GPIOSetValue( PORT0, 2, 1 );
#endif
}
else /* port 号 1 */
{
LPC_SYSCON->PRESETCTRL |= (0x1<<2);
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<18);
/* 除以 2 */
LPC_SYSCON->SSP1CLKDIV = 0x02;
LPC_IOCON->PIO2_2 &= ~0x07; /* SSP I/O 配置 */
LPC_IOCON->PIO2_2 |= 0x02; /* SSP MISO */
LPC_IOCON->PIO2_3 &= ~0x07;
LPC_IOCON->PIO2_3 |= 0x02; /* SSP MOSI */
LPC_IOCON->PIO2_1 &= ~0x07;
LPC_IOCON->PIO2_1 |= 0x02; /* SSP CLK */
#if USE_CS
LPC_IOCON->PIO2_0 &= ~0x07;
LPC_IOCON->PIO2_0 |= 0x02; /* SSP SSEL */
#else
/* Enable AHB clock to the GPIO domain. */
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
LPC_IOCON->PIO2_0 &= ~0x07; /* SSP SSEL 为 GPIO 引脚 */
/* port2, 第 0 位设置为 GPIO 输出并为高 */
GPIOSetDir( PORT2, 0, 1 );
GPIOSetValue( PORT2, 0, 1 );
#endif
}
return;
}
/**
* 函数名: SSP_Init
* 描述: SSP 端口常规初始化
* 参数: 无
* 返回值: 无
*/
void SSP_Init( uint8_t portNum )
{
uint8_t i, Dummy=Dummy;
if ( portNum == 0 )
{
/* 设置 DSS 数据位 8-位, 帧格式 SPI, CPOL = 0, CPHA = 0, SCR 为 15 */
LPC_SSP0->CR0 = 0x0707;
/* SSPCPSR 时钟分频器,主模式,最小分频系数 0x02 */
LPC_SSP0->CPSR = 0x2;
for ( i = 0; i < FIFOSIZE; i++ )
{
/* 清除 RxFIFO */
Dummy = LPC_SSP0->DR;
}
/* 使能 SSP 中断 */
NVIC_EnableIRQ(SSP0_IRQn);
/* 选中为主器件, SSP 使能 */
#if LOOPBACK_MODE
LPC_SSP0->CR1 = SSPCR1_LBM | SSPCR1_SSE;
#else
#if SSP_SLAVE
/* 从模式 */
if ( LPC_SSP0->CR1 & SSPCR1_SSE )
{
/* 从模式位不能被设置直到 SSE 位为 0. */
LPC_SSP0->CR1 &= ~SSPCR1_SSE;
}
/* 先使能从模式位 */
LPC_SSP0->CR1 = SSPCR1_MS;
/* 使能 SSP */
LPC_SSP0->CR1 |= SSPCR1_SSE;
#else
/* 主模式 */
LPC_SSP0->CR1 = SSPCR1_SSE;
#endif
#endif
/* 设置 SSPINMS 寄存器使能中断 */
/* 使能相关中断的所有错误 */
LPC_SSP0->IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM;
}
else
{
/* 设置 DSS 数据位 8-位, 帧格式 SPI, CPOL = 0, CPHA = 0, SCR 为 15 */
LPC_SSP1->CR0 = 0x0707;
/* SSPCPSR 时钟预分频器寄存器,主模式, 最小分频系数 0x02 */
LPC_SSP1->CPSR = 0x2;
for ( i = 0; i < FIFOSIZE; i++ )
{
/* 清除 RxFIFO */
Dummy = LPC_SSP1->DR;
}
/* 使能 SSP 中断 */
NVIC_EnableIRQ(SSP1_IRQn);
/* 选定为主器件, SSP 使能 */
#if LOOPBACK_MODE
LPC_SSP1->CR1 = SSPCR1_LBM | SSPCR1_SSE;
#else
#if SSP_SLAVE
/* Slave mode */
if ( LPC_SSP1->CR1 & SSPCR1_SSE )
{
/* 从模式位不能被设置直到 SSE 位为 0. */
LPC_SSP1->CR1 &= ~SSPCR1_SSE;
}
/* 先使能从模式位 */
LPC_SSP1->CR1 = SSPCR1_MS;
/* 使能 SSP */
LPC_SSP1->CR1 |= SSPCR1_SSE;
#else
/* 主模式 */
LPC_SSP1->CR1 = SSPCR1_SSE;
#endif
#endif
/* 设置 SSPINMS 寄存器使能中断 */
/* 使能所有中断相关的错误 */
LPC_SSP1->IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM;
}
return;
}
/**
* 函数名: SSP_Send
* 描述: 发送一块数据到 SSP 端口。
* 参数: 端口号 #,缓冲区指针, 块长度
* 返回值: 无
*/
void SSP_Send( uint8_t portNum, uint8_t *buf, uint32_t Length )
{
uint32_t i;
uint8_t Dummy = Dummy;
for ( i = 0; i < Length; i++ )
{
if ( portNum == 0 )
{
/* 继续执行仅当总线不忙, TX FIFO 非满 */
while ( (LPC_SSP0->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF );
LPC_SSP0->DR = *buf;
buf++;
#if !LOOPBACK_MODE
while ( (LPC_SSP0->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
/* 每当写入一个字节, MISO FIFO 计数器加一, 清除 FIFO
MISO. 否则, 当 SSP0Receive() 调用时, 先前的数据字节仍会留在
FIFO. */
Dummy = LPC_SSP0->DR;
#else
/* 等待直到忙位被清除。 */
while ( LPC_SSP0->SR & SSPSR_BSY );
#endif
}
else
{
/* 继续执行仅当总线不忙, TX FIFO 非满 */
while ( (LPC_SSP1->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF );
LPC_SSP1->DR = *buf;
buf++;
#if !LOOPBACK_MODE
while ( (LPC_SSP1->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
/* 每当写入一个字节, MISO FIFO 计数器加一, 清除 FIFO
MISO. 否则, 当 SSP0Receive() 调用时, 先前的数据字节仍会留在
FIFO. */
Dummy = LPC_SSP1->DR;
#else
/* 等待直到忙位被清除。 */
while ( LPC_SSP1->SR & SSPSR_BSY );
#endif
}
}
return;
}
/**
* 函数名: SSP_Receive
* 描述: 该模块接收从 SSP 接收一块数据
* 参数: 端口 #, 缓冲区指针, 块长度
* 返回值: None
*/
void SSP_Receive( uint8_t portNum, uint8_t *buf, uint32_t Length )
{
uint32_t i;
for ( i = 0; i < Length; i++ )
{
/* 只要接收 FIFO 非空,能够一直接收. */
/* 如果不是回环测试, TX 和 RX 共享时钟,不需要写假数据获得时钟
得到数据 */
/* 如果是 点到点 通信, SPDR 在读操作之前需要被写 */
if ( portNum == 0 )
{
#if !LOOPBACK_MODE
#if SSP_SLAVE
while ( !(LPC_SSP0->SR & SSPSR_RNE) );
#else
LPC_SSP0->DR = 0xFF;
/* 等待直到 忙 位被清除 */
while ( (LPC_SSP0->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
#endif
#else
while ( !(LPC_SSP0->SR & SSPSR_RNE) );
#endif
*buf = LPC_SSP0->DR;
buf++;
}
else
{
#if !LOOPBACK_MODE
#if SSP_SLAVE
while ( !(LPC_SSP1->SR & SSPSR_RNE) );
#else
LPC_SSP1->DR = 0xFF;
/* 等待直到 忙 位被清除 */
while ( (LPC_SSP1->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
#endif
#else
while ( !(LPC_SSP1->SR & SSPSR_RNE) );
#endif
*buf = LPC_SSP1->DR;
buf++;
}
}
return;
}
/**
* @}
*/
/**
* @}
*/
/************* (C) COPYRIGHT 2010 Wuhan R&D Center, Embest *****文件结束*******/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -