Test application for getting the Nucleo F0 30 board to work with Evan's prototype LED board.

Dependencies:   mbed

main.cpp

Committer:
bgrissom
Date:
2014-08-08
Revision:
6:e4da8955cf65
Parent:
5:9a662dec2ddb

File content as of revision 6:e4da8955cf65:

#include "mbed.h" 

#define OK    (0)
#define ERROR (-1)

#define PIN_41 PB_5
#define PIN_46 PB_9
#define PIN_32 PA_11
#define PIN_20 PB_2
#define HEX_ONE_THOUSAND (0x03E8)

DigitalOut ENA(PIN_41);
DigitalOut ENB(PIN_46);
DigitalOut ENC(PIN_32);
DigitalOut EnSclk(PIN_20);


// Forward Declarations
void pwmout_period_ns(pwmout_t* obj, int us);
int  cmd_S0(uint16_t value);
void cmd_S1(void);

// Globals
bool gSpiMode = false;
SPI* gSpiPtr = NULL;
DigitalOut gbbTRANS(PA_4); // Global bit bang TRANS (data) line
const int SCLK_ENABLED = 0;


int main() {
    ENA = 1;
    ENB = 1;
    ENC = 1;
    EnSclk = SCLK_ENABLED;


    // NOTE: 24MHz is half the 48MHz clock rate.  The PWM registers
    //       seem to only allow 24MHz at this point, so I'm matching
    //       the SPI bus speed to be the same.
    //
    //       1/24MHz  =>  1/(24*10^6)  =>  41.6*10^-9 second period,
    //       which means 41.6ns period and 20.8ns pulse width at
    //       50% duty cycle (which seems to be right for the SPI clock
    //       line as well as a reasonable choice for the PWM line).

    // BAG ORIG: gbbTRANS = 1; // Start with TRANS high.  It acts like a SPI slave select
                  // that is active-low.
    gbbTRANS = 0;

    // PWMCLK
    pwmout_t outs;
    pwmout_init(&outs, PB_4);
    pwmout_period_ns(&outs, 2); // 24 MHz (not very clean on the scope)
    // pwmout_period_ns(&outs, 40); // 1.2 MHz on the scope
    // Very slow!  pwmout_period_us(&outs, 2);
    pwmout_write(&outs, 0.5f);

    int ret = OK; // Return value
    int i = 0;

    printf("17:10\n");

    //while (1) {
        for (i=0; i<400; i++) {
            ret = cmd_S0(0x0900);
            // ORIG: ret = cmd_S0(0xFFFF);
            if (ret != OK) {
                printf("ERROR cmd_S0()\n");
                return ERROR;
            }
        }
        cmd_S1();
    //}
}



// S0 Command:
//      Needs only SCK and SIN (which are SPI_SCK and SPI_MOSI respectively).
//      This is because TRANS can be 0 for this command according to the datasheet.
int cmd_S0(uint16_t value) {
        // Command S0 and S1 share the same clock line, so we need to be
        // careful which mode we are in.  This avoids re-initializing these
        // pins if we are already in SPI mode.
        // WARNING: Re-initializing every time makes the MOSI line dirty and
        //          is wasteful for the CPU.
        if ( gSpiMode == false &&
             gSpiPtr  == NULL)
        {
            // We are not using MISO, this is a one-way bus
            gSpiPtr = new SPI(SPI_MOSI, NC, SPI_SCK);

            if (gSpiPtr == NULL) {
                printf("ERROR: Could not allocate SPI\n");
                return ERROR;
            }

            // Note: Polarity and phase are both 0 for the TC62D723FNG
            // For a graphical reminder on polarity and phase, visit:
            //     http://www.eetimes.com/document.asp?doc_id=1272534
            gSpiPtr->format(16, 0);
            // gSpiPtr->frequency(1000000);  // 1.5 MHz on the scope
            gSpiPtr->frequency(24000000); // 24 MHz
            gSpiMode = true;
        }
        gbbTRANS = 0; // Like an SPI slave select
        gSpiPtr->write(value);
        gbbTRANS = 1; // Like an SPI slave select
        // LONGTERM OPTIMIZATION: Evan suggests setting it 
        // wait_us(1);
        // gbbTRANS = 0; // Set back low
        return OK;
}



void cmd_S1(void) {
    int i = 0;
    int j = 0;
    
    gbbTRANS = 0; // FIXME
    
    if ( gSpiMode == true &&
         gSpiPtr  != NULL)
    {
        delete gSpiPtr;
        gSpiPtr  = NULL;
        gSpiMode = false;
    }
    
    DigitalOut bbSCK (D13); // bit bang clock

    bbSCK    = 0; // Start off/low
    gbbTRANS = 1; // Set high

    // Loop 6 times = 3 clock cycles
    for (j=0; j<6; j++) { // Always use an even number here!
        // The order of these two lines matter!
        i == 0 ? i = 1 : i = 0;          // Toggle i
        i == 0 ? bbSCK = 0 : bbSCK = 1;  // Set SCK to the same value as i
    }
    gbbTRANS = 0; // Set low
}


/* USED FOR THE F030 BOARD
// This code is based off:
// mbed/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F030R8/pwmout_api.c  pwmout_period_us()
void pwmout_period_ns_NOT_USED(pwmout_t* obj, int us) {
    TIM_TypeDef *tim = (TIM_TypeDef *)(obj->pwm);
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    float dc = pwmout_read(obj);

    TIM_Cmd(tim, DISABLE);

    obj->period = us;

    TIM_TimeBaseStructure.TIM_Period = obj->period - 1;
    // Orig code:  TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 µs tick
    TIM_TimeBaseStructure.TIM_Prescaler = 0;  // BAG 1 ns tick (?)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(tim, &TIM_TimeBaseStructure);

    // Set duty cycle again
    pwmout_write(obj, dc);

    TIM_ARRPreloadConfig(tim, ENABLE);

    TIM_Cmd(tim, ENABLE);
}
*/


static TIM_HandleTypeDef TimHandleBAG;

void pwmout_write_BAG(pwmout_t* obj, float value) {
    TIM_OC_InitTypeDef sConfig;
    int channel = 0;
    int complementary_channel = 0;

    TimHandleBAG.Instance = (TIM_TypeDef *)(obj->pwm);

    if (value < (float)0.0) {
        value = 0.0;
    } else if (value > (float)1.0) {
        value = 1.0;
    }

    obj->pulse = (uint32_t)((float)obj->period * value);

    // Configure channels
    sConfig.OCMode       = TIM_OCMODE_PWM1;
    sConfig.Pulse        = obj->pulse;
    sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
    sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
    sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
    sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;

    switch (obj->pin) {
        // Channels 1
        case PA_2:
        case PA_4:
        case PA_6:
        case PA_7:
        case PA_8:
        case PB_1:
        case PB_4:
        case PB_8:
        case PB_9:
        case PB_14:
        case PC_6:
            channel = TIM_CHANNEL_1;
            break;
        // Channels 1N
        case PA_1:
        case PB_6:
        case PB_7:
        case PB_13:
            channel = TIM_CHANNEL_1;
            complementary_channel = 1;
            break;
        // Channels 2
        case PA_3:
        case PA_9:
        case PB_5:
        case PB_15:
        case PC_7:
            channel = TIM_CHANNEL_2;
            break;
        // Channels 3
        case PA_10:
        case PB_0:
        case PC_8:
            channel = TIM_CHANNEL_3;
            break;
        // Channels 4
        case PA_11:
        case PC_9:
            channel = TIM_CHANNEL_4;
            break;
        default:
            return;
    }

    HAL_TIM_PWM_ConfigChannel(&TimHandleBAG, &sConfig, channel);

    if (complementary_channel) {
        HAL_TIMEx_PWMN_Start(&TimHandleBAG, channel);
    } else {
        HAL_TIM_PWM_Start(&TimHandleBAG, channel);
    }
}


void pwmout_period_ns(pwmout_t* obj, int us) {
    TimHandleBAG.Instance = (TIM_TypeDef *)(obj->pwm);

    float dc = pwmout_read(obj);

    __HAL_TIM_DISABLE(&TimHandleBAG);

    // Update the SystemCoreClock variable
    SystemCoreClockUpdate();

    TimHandleBAG.Init.Period        = us - 1;
    // BAG Orig:  TimHandle.Init.Prescaler     = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 µs tick
    TimHandleBAG.Init.Prescaler     = 0; // BAG 1 ns tick (?)
    TimHandleBAG.Init.ClockDivision = 0;
    TimHandleBAG.Init.CounterMode   = TIM_COUNTERMODE_UP;
    HAL_TIM_PWM_Init(&TimHandleBAG);

    // Set duty cycle again
    pwmout_write_BAG(obj, dc);

    // Save for future use
    obj->period = us;

    __HAL_TIM_ENABLE(&TimHandleBAG);
}