TaterLi's LazyBlog

自言自语,不喜绕路,科学上网,远离天国.

@TaterLi4月前

11/3
15:55
技术控

LPC43XX SGPIO 发生 PWM

SGPIO就是串行GPIO的意思,这里的串行GPIO跟Intel的SGPIO是两码事,Intel的SGPIO顶多叫USCI(通用串行通信外设),这个SGPIO就是真的串行,下面用最简单的PWM发生来说.

首先只能做很简单分辨率的PWM,SGPIO也是有个输入时钟的,这个可以定性认为是整个频率,即.

把这一段定量分成32份.

因为SGPIO是移位匹配寄存器(我发明的名词)

 

比如我设置成0x00000001,那么就是0位置是1,匹配到0位置是1,那么DOUT为1,其他位置是0,所以DOUT是0,假设我们寄存器是0xAAAAAAAA,那么就是移到BIT0的时候0,然后BIT1被拉1.

我现在取值是0x00000001.注意红框位置.

#include "LPC43xx.h"


/* Variables ------------------------------------------------------------------*/
uint8_t chan = 0;															//Variable used to get settings from the SGPIOPWMValue to the interrupt handler
uint8_t val = 0;															//Variable used to get settings from the SGPIOPWMValue to the interrupt handler
uint8_t intcount = 0;													//Variable used to count how many times REG_SS was updated
uint32_t PWMValues[0x21] =  									//All the 33 PWM values used for PWM
{
    0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
    0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF,
    0x000003FF, 0x000007FF, 0x00000FFF, 0x00001FFF, 0x00003FFF,
    0x00007FFF, 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
    0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
    0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, 0x1FFFFFFF,
    0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
};

/*********************************************************************//**
 * @brief 		Change PWM value of an SGPIO pin
 * @param[in]	value			Should be between 0 and 33, 0 is off, 33 is on, 16 is ~50% PWM
 * @param[in]	channel		SGPIO channel that should be changed
 * @return		None
 **********************************************************************/
void SGPIOPWMValue(uint8_t value, uint8_t channel)
{
    chan = channel;												//Put the values into globab variables so the interrupt handler can reach it
    val = value;
    LPC_SGPIO->CLR_STATUS_1 = 0xFFFF;		//Clear the interrupts
    LPC_SGPIO->SET_EN_1 = 0x8000;					//interrupt when slice 15 switches data register
}

void SGPIOPWMchaninit(uint32_t freq, uint8_t channel)
{
    //Calculate the correct divider setting
    uint32_t calceddivider = 0;													//Variable to calculate the PWM frequency
    calceddivider = 204000000;
    calceddivider = (calceddivider / freq) - 1;
    calceddivider = calceddivider / 0x20;

    //Setup an SGPIO channel for PWM
    LPC_SGPIO->OUT_MUX_CFG[channel] = 0x00000000;				//one bit mode
    LPC_SGPIO->SGPIO_MUX_CFG[channel] = (0x1 << 11);		//internal clock, concave on
    LPC_SGPIO->SLICE_MUX_CFG[channel] = 0x0;						//Interrupt on match on
    LPC_SGPIO->PRESET[channel] = calceddivider;					//clock speed = ((supplied clock / 2) / (preset + 1))
    LPC_SGPIO->COUNT[channel] = 0x0;
    LPC_SGPIO->POS[channel] = 0x1F00;										//after 32 clocks, switch data registers,
    LPC_SGPIO->REG[channel] = 0xFFFFF;									//Data in normal register, not important for now
    LPC_SGPIO->REG_SS[channel] = 0xFFFFF;								//Data in shadow register, used for match
}

void SGPIOPWMinit(void)
{
    LPC_SGPIO->CLR_EN_0	= 0xffff;									// disable interrupting on clock
    LPC_SGPIO->CLR_EN_1	= 0xffff;									// disable interrupting on clock
    LPC_SGPIO->CLR_EN_2	= 0xffff;									// disable interrupting on clock
    LPC_SGPIO->CLR_EN_3	= 0xffff;									// disable interrupting on clock

    LPC_SGPIO->GPIO_OENREG = 0xFFFF;							//All SGPIO's as output
    LPC_SGPIO->CTRL_ENABLE = 0xFFFF;							//Enable all SGPIO clocks.
    NVIC_EnableIRQ(SGPIO_IRQn);        			//Enable SGPIO Interrupt
}

void SGPIO_IRQHandler (void)                    //Handles all SGPIO interrupts
{
    uint32_t interruptvar = 0;										//Variable used to store the interrupt value, what slice had an interrupt.
    interruptvar = LPC_SGPIO->STATUS_1;

    if (interruptvar & (1 << chan))								//Check if the correct channel got an data swap interrupt
    {
        LPC_SGPIO->REG_SS[chan] = PWMValues[val];		//Place the new value in the REG_SS rgister
        intcount += 1;															//Add one to the counter
        LPC_SGPIO->CLR_STATUS_1 =  0xFFFF;					//Clear the interrupts
        if(intcount >= 2)														//When the counter is 2 the REG_SS register has been updated twice
        {
            LPC_SGPIO->SET_EN_1 = 0x0000;							//Stop the interrupts
            LPC_SGPIO->CLR_EN_1	= 0xffff;							//And clear the interrupt
            intcount = 0;															//Clear the counter
        }
    }
}

uint8_t SGPIOPWMstatus(void)
{
    return intcount;
}

int main(void)
{
    LPC_SCU->SFSP1_1 = 0x03; /* 关闭上拉 + FUNC3 */

    SGPIOPWMinit();
    SGPIOPWMchaninit(100000, 1);
    SGPIOPWMValue(0x01, 1);
    while (1)
    {

    }
}

所以生成的波形,就如最初的截图一样,我改成0xAAAAAAAA大家看看.

可见,匹配到就会显示电平,所以,这是一个PWM Val从0~32可调的PWM,算是准5Bit PWM了.他就是一个路过,检测到1还是0,就会发送.这让我想起了单线SPI(只有MOSI,又是我发明新名词了.),调制MOSI数据到32Bit,然后他自己发出去,然后其他几个SGPIO发送SCLK.当然DIN也是存入REG的.也就是两个SGPIO互相独立(软件上),工作上却看起来协作.


遗留问题:

  1. SGPIO SLICE,决定IO怎么排布.
  2. SGPIO 非1Bit Mode.是不是可以模拟QSPI.

LPC43XX SGPIO 发生 PWM