808 lines
23 KiB
C
808 lines
23 KiB
C
//#############################################################################
|
|
//
|
|
// FILE: pmbus.c
|
|
//
|
|
// TITLE: C28x PMBUS driver
|
|
//
|
|
//#############################################################################
|
|
// $TI Release: F2838x Support Library v3.04.00.00 $
|
|
// $Release Date: Fri Feb 12 19:08:49 IST 2021 $
|
|
// $Copyright:
|
|
// Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
//
|
|
// Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the
|
|
// distribution.
|
|
//
|
|
// Neither the name of Texas Instruments Incorporated nor the names of
|
|
// its contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
// $
|
|
//#############################################################################
|
|
|
|
#include "pmbus.h"
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Globals
|
|
//
|
|
//*****************************************************************************
|
|
#if PMBUS_INCLUDE_CRC8_TABLE == 0x1U
|
|
|
|
//
|
|
// CRC table for the polynomial x^8+x^2+x^1+1 (0x7). File scope only
|
|
//
|
|
const uint16_t PMBus_crc8Table[256U] = {
|
|
0x00U, 0x07U, 0x0EU, 0x09U, 0x1CU, 0x1BU, 0x12U, 0x15U,
|
|
0x38U, 0x3FU, 0x36U, 0x31U, 0x24U, 0x23U, 0x2AU, 0x2DU,
|
|
0x70U, 0x77U, 0x7EU, 0x79U, 0x6CU, 0x6BU, 0x62U, 0x65U,
|
|
0x48U, 0x4FU, 0x46U, 0x41U, 0x54U, 0x53U, 0x5AU, 0x5DU,
|
|
0xE0U, 0xE7U, 0xEEU, 0xE9U, 0xFCU, 0xFBU, 0xF2U, 0xF5U,
|
|
0xD8U, 0xDFU, 0xD6U, 0xD1U, 0xC4U, 0xC3U, 0xCAU, 0xCDU,
|
|
0x90U, 0x97U, 0x9EU, 0x99U, 0x8CU, 0x8BU, 0x82U, 0x85U,
|
|
0xA8U, 0xAFU, 0xA6U, 0xA1U, 0xB4U, 0xB3U, 0xBAU, 0xBDU,
|
|
0xC7U, 0xC0U, 0xC9U, 0xCEU, 0xDBU, 0xDCU, 0xD5U, 0xD2U,
|
|
0xFFU, 0xF8U, 0xF1U, 0xF6U, 0xE3U, 0xE4U, 0xEDU, 0xEAU,
|
|
0xB7U, 0xB0U, 0xB9U, 0xBEU, 0xABU, 0xACU, 0xA5U, 0xA2U,
|
|
0x8FU, 0x88U, 0x81U, 0x86U, 0x93U, 0x94U, 0x9DU, 0x9AU,
|
|
0x27U, 0x20U, 0x29U, 0x2EU, 0x3BU, 0x3CU, 0x35U, 0x32U,
|
|
0x1FU, 0x18U, 0x11U, 0x16U, 0x03U, 0x04U, 0x0DU, 0x0AU,
|
|
0x57U, 0x50U, 0x59U, 0x5EU, 0x4BU, 0x4CU, 0x45U, 0x42U,
|
|
0x6FU, 0x68U, 0x61U, 0x66U, 0x73U, 0x74U, 0x7DU, 0x7AU,
|
|
0x89U, 0x8EU, 0x87U, 0x80U, 0x95U, 0x92U, 0x9BU, 0x9CU,
|
|
0xB1U, 0xB6U, 0xBFU, 0xB8U, 0xADU, 0xAAU, 0xA3U, 0xA4U,
|
|
0xF9U, 0xFEU, 0xF7U, 0xF0U, 0xE5U, 0xE2U, 0xEBU, 0xECU,
|
|
0xC1U, 0xC6U, 0xCFU, 0xC8U, 0xDDU, 0xDAU, 0xD3U, 0xD4U,
|
|
0x69U, 0x6EU, 0x67U, 0x60U, 0x75U, 0x72U, 0x7BU, 0x7CU,
|
|
0x51U, 0x56U, 0x5FU, 0x58U, 0x4DU, 0x4AU, 0x43U, 0x44U,
|
|
0x19U, 0x1EU, 0x17U, 0x10U, 0x05U, 0x02U, 0x0BU, 0x0CU,
|
|
0x21U, 0x26U, 0x2FU, 0x28U, 0x3DU, 0x3AU, 0x33U, 0x34U,
|
|
0x4EU, 0x49U, 0x40U, 0x47U, 0x52U, 0x55U, 0x5CU, 0x5BU,
|
|
0x76U, 0x71U, 0x78U, 0x7FU, 0x6AU, 0x6DU, 0x64U, 0x63U,
|
|
0x3EU, 0x39U, 0x30U, 0x37U, 0x22U, 0x25U, 0x2CU, 0x2BU,
|
|
0x06U, 0x01U, 0x08U, 0x0FU, 0x1AU, 0x1DU, 0x14U, 0x13U,
|
|
0xAEU, 0xA9U, 0xA0U, 0xA7U, 0xB2U, 0xB5U, 0xBCU, 0xBBU,
|
|
0x96U, 0x91U, 0x98U, 0x9FU, 0x8AU, 0x8DU, 0x84U, 0x83U,
|
|
0xDEU, 0xD9U, 0xD0U, 0xD7U, 0xC2U, 0xC5U, 0xCCU, 0xCBU,
|
|
0xE6U, 0xE1U, 0xE8U, 0xEFU, 0xFAU, 0xFDU, 0xF4U, 0xF3U,
|
|
};
|
|
#endif //PMBUS_INCLUDE_CRC8_TABLE == 0x1U
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_getInterruptStatus
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
PMBus_getInterruptStatus(uint32_t base)
|
|
{
|
|
uint32_t intStatus;
|
|
|
|
//
|
|
// Create a bit mask of all the interrupt sources
|
|
//
|
|
const uint32_t bitmask = (
|
|
PMBUS_PMBSTS_DATA_READY |
|
|
PMBUS_PMBSTS_DATA_REQUEST |
|
|
PMBUS_PMBSTS_EOM |
|
|
PMBUS_PMBSTS_CLK_LOW_TIMEOUT |
|
|
PMBUS_PMBSTS_CLK_HIGH_DETECTED |
|
|
PMBUS_PMBSTS_SLAVE_ADDR_READY |
|
|
PMBUS_PMBSTS_BUS_FREE |
|
|
PMBUS_PMBSTS_LOST_ARB |
|
|
PMBUS_PMBSTS_ALERT_EDGE |
|
|
PMBUS_PMBSTS_CONTROL_EDGE
|
|
);
|
|
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
|
|
intStatus = HWREG(base + PMBUS_O_PMBSTS) & 0x0003FFFFU;
|
|
|
|
//
|
|
// Mask off bits that are not an interrupt source and return
|
|
//
|
|
return(intStatus & bitmask);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_initSlaveMode
|
|
//
|
|
//*****************************************************************************
|
|
void PMBus_initSlaveMode(uint32_t base, uint16_t address, uint16_t mask)
|
|
{
|
|
//
|
|
// Locals
|
|
//
|
|
uint32_t interruptState;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
ASSERT(address <= 0x7FU);
|
|
ASSERT(mask <= 0x7FU);
|
|
|
|
EALLOW;
|
|
|
|
//
|
|
// Save off the interrupt state and disable them
|
|
//
|
|
interruptState = HWREG(base + PMBUS_O_PMBINTM);
|
|
HWREG(base + PMBUS_O_PMBINTM) = PMBUS_INT_ALL;
|
|
|
|
//
|
|
// PMBUS comes out of rest with slave mode enabled. Disable master mode,
|
|
// if set, and enable master mode
|
|
//
|
|
HWREG(base + PMBUS_O_PMBCTRL) &= ~(uint32_t)PMBUS_ENABLE_MASTER_MODE;
|
|
HWREG(base + PMBUS_O_PMBCTRL) |= PMBUS_ENABLE_SLAVE_MODE;
|
|
|
|
//
|
|
// Zero out the slave address and mask first
|
|
//
|
|
HWREG(base + PMBUS_O_PMBSC) &= (~(uint32_t)PMBUS_PMBSC_SLAVE_ADDR_M &
|
|
~(uint32_t)PMBUS_PMBSC_SLAVE_MASK_M);
|
|
|
|
|
|
//
|
|
// Write the address and mask to PMBSC
|
|
//
|
|
HWREG(base + PMBUS_O_PMBSC) |= ((((uint32_t)address <<
|
|
PMBUS_PMBSC_SLAVE_ADDR_S) &
|
|
PMBUS_PMBSC_SLAVE_ADDR_M) |
|
|
(((uint32_t)mask <<
|
|
PMBUS_PMBSC_SLAVE_MASK_S) &
|
|
PMBUS_PMBSC_SLAVE_MASK_M));
|
|
|
|
//
|
|
// Restore the interrupt status
|
|
//
|
|
HWREG(base + PMBUS_O_PMBINTM) = interruptState;
|
|
|
|
EDIS;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_configSlave
|
|
//
|
|
//*****************************************************************************
|
|
void PMBus_configSlave(uint32_t base, uint32_t configWord)
|
|
{
|
|
//
|
|
// Locals
|
|
//
|
|
uint32_t interruptState;
|
|
|
|
//
|
|
// Form a bit mask of the bit fields configWord changes
|
|
//
|
|
const uint32_t bitmask = (PMBUS_PMBSC_MAN_SLAVE_ACK | PMBUS_PMBSC_PEC_ENA |
|
|
PMBUS_PMBSC_MAN_CMD | PMBUS_PMBSC_RX_BYTE_ACK_CNT_M);
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
|
|
EALLOW;
|
|
|
|
//
|
|
// Save off the interrupt state and disable them
|
|
//
|
|
interruptState = HWREG(base + PMBUS_O_PMBINTM);
|
|
HWREG(base + PMBUS_O_PMBINTM) = PMBUS_INT_ALL;
|
|
|
|
//
|
|
// Zero out the bit fields that are changed by configWord, preserve the
|
|
// rest that is, address and mask
|
|
//
|
|
HWREG(base + PMBUS_O_PMBSC) &= ~bitmask;
|
|
|
|
//
|
|
// Write the user configured bit fields (passed in configWord)
|
|
// do not alter address and mask
|
|
//
|
|
HWREG(base + PMBUS_O_PMBSC) |= (configWord & bitmask);
|
|
|
|
//
|
|
// Restore the interrupt status
|
|
//
|
|
HWREG(base + PMBUS_O_PMBINTM) = interruptState;
|
|
|
|
EDIS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_putSlaveData
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
PMBus_putSlaveData(uint32_t base, uint16_t *buffer, uint16_t nBytes,
|
|
bool txPEC)
|
|
{
|
|
//
|
|
// Locals
|
|
//
|
|
uint16_t i = 0U;
|
|
uint32_t tx_data = 0U;
|
|
uint32_t command;
|
|
uint16_t *pBuffer = buffer;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
ASSERT((nBytes > 0U) && (nBytes <= 4U));
|
|
ASSERT((txPEC == true) || (txPEC == false));
|
|
EALLOW;
|
|
|
|
//
|
|
// Read the existing Slave configuration, mask out the TX count
|
|
//
|
|
command = HWREG(base + PMBUS_O_PMBSC);
|
|
command &= ~PMBUS_PMBSC_TX_COUNT_M;
|
|
|
|
//
|
|
// Update the transmit count and place the data into the transmit register.
|
|
//
|
|
command |= (((uint32_t)nBytes << PMBUS_PMBSC_TX_COUNT_S) &
|
|
PMBUS_PMBSC_TX_COUNT_M);
|
|
if(txPEC == 1U)
|
|
{
|
|
command |= PMBUS_PMBSC_TX_PEC;
|
|
}
|
|
else
|
|
{
|
|
command &= ~(uint32_t)PMBUS_PMBSC_TX_PEC;
|
|
}
|
|
|
|
//
|
|
// Write to the Slave Config register
|
|
//
|
|
HWREG(base + PMBUS_O_PMBSC) = command;
|
|
EDIS;
|
|
|
|
//
|
|
// Construct the transmit long word
|
|
//
|
|
while(i < nBytes)
|
|
{
|
|
tx_data |= (((uint32_t)*pBuffer & 0x000000FFUL) <<
|
|
((uint32_t)i << 0x3U));
|
|
i++;
|
|
pBuffer++;
|
|
}
|
|
|
|
HWREG(base + PMBUS_O_PMBTXBUF) = tx_data;
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_ackAddress
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
PMBus_ackAddress(uint32_t base, uint32_t address, uint32_t status,
|
|
uint16_t *buffer)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
ASSERT(address <= 0x7FUL);
|
|
|
|
//
|
|
// Check if manual slave acknowledge mode is enabled
|
|
//
|
|
ASSERT((HWREG(base + PMBUS_O_PMBSC) & PMBUS_PMBSC_MAN_SLAVE_ACK) != 0U);
|
|
|
|
if((status & (uint32_t)PMBUS_PMBSTS_SLAVE_ADDR_READY) != 0U)
|
|
{
|
|
//
|
|
// Read the receive buffer
|
|
//
|
|
(void)PMBus_getSlaveData(base, &buffer[0], status);
|
|
|
|
//
|
|
// Compare the low byte, the address, to the arguments
|
|
//
|
|
if((buffer[0] & 0x7FU) == address)
|
|
{
|
|
//
|
|
// Acknowledge
|
|
//
|
|
HWREG(base + PMBUS_O_PMBACK) |= PMBUS_PMBACK_ACK;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// NACK
|
|
//
|
|
HWREG(base + PMBUS_O_PMBACK) &= ~(uint32_t)PMBUS_PMBACK_ACK;
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_ackCommand
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
PMBus_ackCommand(uint32_t base, uint32_t command, uint32_t status,
|
|
uint16_t *buffer)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
ASSERT(command <= 0xFFUL);
|
|
|
|
//
|
|
// Check if manual slave acknowledge mode is enabled
|
|
//
|
|
ASSERT((HWREG(base + PMBUS_O_PMBSC) & PMBUS_PMBSC_MAN_CMD) == 0U);
|
|
|
|
if((status & (uint32_t)PMBUS_PMBSTS_DATA_REQUEST) != 0U)
|
|
{
|
|
//
|
|
// Read the receive buffer
|
|
//
|
|
(void)PMBus_getSlaveData(base, &buffer[0], status);
|
|
|
|
//
|
|
// Compare the low byte, the address, to the arguments
|
|
//
|
|
if((buffer[0] & 0xFFU) == command)
|
|
{
|
|
//
|
|
// Acknowledge
|
|
//
|
|
HWREG(base + PMBUS_O_PMBACK) |= PMBUS_PMBACK_ACK;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// NACK
|
|
//
|
|
HWREG(base + PMBUS_O_PMBACK) &= ~(uint32_t)PMBUS_PMBACK_ACK;
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_initMasterMode
|
|
//
|
|
//*****************************************************************************
|
|
void PMBus_initMasterMode(uint32_t base)
|
|
{
|
|
//
|
|
// Locals
|
|
//
|
|
uint32_t interruptState;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
|
|
EALLOW;
|
|
|
|
//
|
|
// Save off the interrupt state and disable them
|
|
//
|
|
interruptState = HWREG(base + PMBUS_O_PMBINTM);
|
|
HWREG(base + PMBUS_O_PMBINTM) = PMBUS_INT_ALL;
|
|
|
|
//
|
|
// PMBUS comes out of rest with slave mode enabled. Disable slave mode
|
|
// enable master mode
|
|
//
|
|
HWREG(base + PMBUS_O_PMBCTRL) &= ~(uint32_t)PMBUS_ENABLE_SLAVE_MODE;
|
|
HWREG(base + PMBUS_O_PMBCTRL) |= PMBUS_ENABLE_MASTER_MODE;
|
|
|
|
//
|
|
// Restore the interrupt status
|
|
//
|
|
HWREG(base + PMBUS_O_PMBINTM) = interruptState;
|
|
EDIS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_generateCRCTable
|
|
//
|
|
//*****************************************************************************
|
|
void PMBus_generateCRCTable(uint16_t *crcTable)
|
|
{
|
|
register uint16_t i;
|
|
register uint16_t j;
|
|
register uint16_t crc8_accum;
|
|
|
|
for(i = 0U; i < 256U; i++)
|
|
{
|
|
crc8_accum = i;
|
|
for(j = 0U; j < 8U; j++)
|
|
{
|
|
if((crc8_accum & 0x80U) != 0U)
|
|
{
|
|
crc8_accum = ((crc8_accum << 1U) & 0xffU) ^ (uint16_t)0x07U;
|
|
}
|
|
else
|
|
{
|
|
crc8_accum = (crc8_accum << 1U) & 0xffU;
|
|
}
|
|
}
|
|
crcTable[i] = crc8_accum;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_verifyPEC
|
|
//
|
|
//*****************************************************************************
|
|
bool
|
|
PMBus_verifyPEC(uint32_t base, uint16_t *buffer, const uint16_t *crcTable,
|
|
uint16_t byteCount, uint16_t pec)
|
|
{
|
|
register uint16_t i;
|
|
register uint16_t parity = 0U;
|
|
register uint16_t tableIndex;
|
|
register uint16_t accumulator;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
ASSERT(byteCount > 0U);
|
|
ASSERT(pec < 0xFFU);
|
|
|
|
//
|
|
// PEC is always calculated first with the address + R/W bit
|
|
//
|
|
tableIndex = HWREG(base + PMBUS_O_PMBHSA);
|
|
|
|
accumulator = crcTable[tableIndex];
|
|
|
|
//
|
|
// The assumption is the message bytes are packed into 16-bit words
|
|
// and the calculation starts from the low byte
|
|
// The memory arrangement is as follows (ignore the addresses
|
|
// Address|__LB__|__HB__|
|
|
// 0x0000 |__D0__|__D1__|
|
|
// 0x0001 |__D2__|__D3__|
|
|
// 0x0002 |__D4__|__D5__|
|
|
// 0x0003 |__D6__|__D7__|
|
|
// 0x0004 |__D8__|__D9__|
|
|
// ...
|
|
//
|
|
for(i = 0U; i < byteCount; i++)
|
|
{
|
|
//
|
|
// __byte selects either the low(0) or high(1) byte in a word
|
|
// the initial selection provided by the enumeration parity
|
|
// We store each PMBUS byte in the low byte of successive words
|
|
// hence parity is always even (0) and incremented by 2
|
|
//
|
|
|
|
tableIndex = accumulator ^ (uint16_t)__byte((int16_t *)buffer, parity);
|
|
accumulator = crcTable[tableIndex];
|
|
parity += 2U;
|
|
}
|
|
|
|
//
|
|
// Compare the result with the PEC
|
|
//
|
|
return(accumulator == pec);
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_getData
|
|
//
|
|
//*****************************************************************************
|
|
uint16_t
|
|
PMBus_getData(uint32_t base, uint16_t *buffer, uint32_t status)
|
|
{
|
|
|
|
//
|
|
// Locals
|
|
//
|
|
uint32_t temp, i;
|
|
uint16_t num_rx_bytes;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
|
|
//
|
|
// Get the contents of the Receive buffer.
|
|
//
|
|
num_rx_bytes = (uint16_t)((status & PMBUS_PMBSTS_RD_BYTE_COUNT_M) >>
|
|
PMBUS_PMBSTS_RD_BYTE_COUNT_S);
|
|
|
|
if(num_rx_bytes != 0U)
|
|
{
|
|
temp = HWREG(base + PMBUS_O_PMBRXBUF);
|
|
for(i = 0U; i < num_rx_bytes; i++)
|
|
{
|
|
buffer[i] = (uint16_t)(temp & 0x000000FFUL);
|
|
temp = temp >> 8U;
|
|
}
|
|
}
|
|
|
|
return(num_rx_bytes);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_putMasterData
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
PMBus_putMasterData(uint32_t base, uint16_t *buffer, uint16_t nBytes)
|
|
{
|
|
//
|
|
// Locals
|
|
//
|
|
uint16_t i = 0U;
|
|
uint32_t tx_data = 0U;
|
|
uint16_t *pBuffer = buffer;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
ASSERT((nBytes > 0U) && (nBytes <= 4U));
|
|
|
|
while(i < nBytes)
|
|
{
|
|
tx_data |= (((uint32_t)*pBuffer & 0x000000FFUL) <<
|
|
((uint32_t)i << 3U));
|
|
pBuffer++;
|
|
i++;
|
|
}
|
|
|
|
//
|
|
// Write to the transmit register
|
|
//
|
|
HWREG(base + PMBUS_O_PMBTXBUF) = tx_data;
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_configModuleClock
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PMBus_configModuleClock(uint32_t base, uint32_t moduleFrequency,
|
|
uint32_t sysFrequency)
|
|
{
|
|
//
|
|
// Locals
|
|
//
|
|
uint32_t interruptState, clockDivider, calcModuleFreq;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
ASSERT((moduleFrequency >= PMBUS_MODULE_FREQ_MIN) &&
|
|
(moduleFrequency <= PMBUS_MODULE_FREQ_MAX));
|
|
ASSERT((sysFrequency >= PMBUS_SYS_FREQ_MIN) &&
|
|
(sysFrequency <= PMBUS_SYS_FREQ_MAX));
|
|
|
|
EALLOW;
|
|
|
|
//
|
|
// Save off the interrupt state and disable them
|
|
//
|
|
interruptState = HWREG(base + PMBUS_O_PMBINTM);
|
|
HWREG(base + PMBUS_O_PMBINTM) = PMBUS_INT_ALL;
|
|
|
|
//
|
|
// Calculate the clock divider. If the ratio of sysFrequency to
|
|
// moduleFrequency is larger than 32, the divider is set to its maximum
|
|
// possible value
|
|
//
|
|
clockDivider = (sysFrequency / moduleFrequency) - 1U;
|
|
if(clockDivider > 31UL)
|
|
{
|
|
clockDivider = 31UL;
|
|
}
|
|
|
|
//
|
|
// Write to the PMBCTRL register
|
|
//
|
|
HWREG(base + PMBUS_O_PMBCTRL) |=
|
|
((clockDivider << PMBUS_PMBCTRL_CLKDIV_S)
|
|
& PMBUS_PMBCTRL_CLKDIV_M);
|
|
|
|
//
|
|
// Calculate the actual bus frequency
|
|
//
|
|
calcModuleFreq = sysFrequency / (clockDivider + 1U);
|
|
|
|
//
|
|
// Restore the interrupt status
|
|
//
|
|
HWREG(base + PMBUS_O_PMBINTM) = interruptState;
|
|
EDIS;
|
|
return(calcModuleFreq);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// PMBus_configBusClock
|
|
//
|
|
//*****************************************************************************
|
|
bool PMBus_configBusClock(uint32_t base, PMBus_ClockMode mode,
|
|
uint32_t moduleFrequency)
|
|
{
|
|
//
|
|
// Locals
|
|
//
|
|
uint32_t interruptState, clockHighLimit, clockFreq;
|
|
uint32_t clockLowTimeout, clockHighTimeout, timePeriod;
|
|
uint32_t busIdle, setupTime;
|
|
const uint32_t bitmask = PMBUS_PMBCTRL_FAST_MODE;
|
|
bool status = false;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(PMBus_isBaseValid(base));
|
|
ASSERT((moduleFrequency >= PMBUS_MODULE_FREQ_MIN) &&
|
|
(moduleFrequency <= PMBUS_MODULE_FREQ_MAX));
|
|
|
|
EALLOW;
|
|
|
|
//
|
|
// Save off the interrupt state and disable them
|
|
//
|
|
interruptState = HWREG(base + PMBUS_O_PMBINTM);
|
|
HWREG(base + PMBUS_O_PMBINTM) = PMBUS_INT_ALL;
|
|
|
|
//
|
|
// Calculate the period for the module clock in ns
|
|
//
|
|
timePeriod = (uint32_t)1000000000UL / moduleFrequency;
|
|
|
|
//
|
|
// Disable FAST mode
|
|
//
|
|
HWREG(base + PMBUS_O_PMBCTRL) &= ~bitmask;
|
|
|
|
//
|
|
// Set status to true
|
|
//
|
|
status = true;
|
|
|
|
switch(mode)
|
|
{
|
|
//
|
|
// Standard Mode
|
|
// Parameter Timing Value in ns
|
|
// CLK_LOW_LIMIT 5000
|
|
// CLK_HIGH_LIMIT 5000
|
|
// CLK_FREQ 10000
|
|
// START_LIMIT 4700
|
|
// busIdle 50000
|
|
// CLK_HIGH_TIMEOUT_LIMIT 50000
|
|
// CLK_LOW_TIMEOUT_LIMIT 35000000
|
|
// DATA_ACK_SETUP 250
|
|
//
|
|
case PMBUS_CLOCKMODE_STANDARD:
|
|
clockHighLimit = (5000U / timePeriod) - 3U;
|
|
clockFreq = (10000U / timePeriod) - 4U;
|
|
clockLowTimeout = (35000000U / timePeriod) - 1U;
|
|
clockHighTimeout = (50000U / timePeriod) - 1U;
|
|
busIdle = (50000U / timePeriod) - 1U;
|
|
setupTime = (4700U / timePeriod);
|
|
break;
|
|
|
|
//
|
|
// Fast Mode
|
|
// Parameter Timing Value in ns
|
|
// CLK_LOW_LIMIT 1250
|
|
// CLK_HIGH_LIMIT 1250
|
|
// CLK_FREQ 2500
|
|
// START_LIMIT 600
|
|
// busIdle 12500
|
|
// CLK_HIGH_TIMEOUT_LIMIT 50000
|
|
// CLK_LOW_TIMEOUT_LIMIT 35000000
|
|
// DATA_ACK_SETUP 100
|
|
//
|
|
case PMBUS_CLOCKMODE_FAST:
|
|
clockHighLimit = (1250U / timePeriod) - 3U;
|
|
clockFreq = (2500U / timePeriod) - 4U;
|
|
clockLowTimeout = (35000000U / timePeriod) - 1U;
|
|
clockHighTimeout = (50000U / timePeriod) - 1U;
|
|
busIdle = (12500U / timePeriod) - 1U;
|
|
setupTime = (600U / timePeriod);
|
|
HWREG(base + PMBUS_O_PMBCTRL) |= PMBUS_PMBCTRL_FAST_MODE;
|
|
break;
|
|
|
|
default:
|
|
clockHighLimit = 0U;
|
|
clockFreq = 0U;
|
|
clockLowTimeout = 0U;
|
|
clockHighTimeout = 0U;
|
|
busIdle = 0U;
|
|
setupTime = 0U;
|
|
status = false;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Write the above values to their respective registers
|
|
// Override the timing control
|
|
//
|
|
HWREG(base + PMBUS_O_PMBTIMCTL) |= PMBUS_PMBTIMCTL_TIM_OVERRIDE;
|
|
if(status)
|
|
{
|
|
HWREG(base + PMBUS_O_PMBTIMCLK) =
|
|
(((clockHighLimit << PMBUS_PMBTIMCLK_CLK_HIGH_LIMIT_S) &
|
|
PMBUS_PMBTIMCLK_CLK_HIGH_LIMIT_M) |
|
|
((clockFreq << PMBUS_PMBTIMCLK_CLK_FREQ_S) &
|
|
PMBUS_PMBTIMCLK_CLK_FREQ_M));
|
|
HWREG(base + PMBUS_O_PMBTIMLOWTIMOUT) =
|
|
((clockLowTimeout << PMBUS_PMBTIMLOWTIMOUT_CLKLOWTIMOUT_S) &
|
|
PMBUS_PMBTIMLOWTIMOUT_CLKLOWTIMOUT_M);
|
|
HWREG(base + PMBUS_O_PMBTIMHIGHTIMOUT) =
|
|
((clockHighTimeout << PMBUS_PMBTIMHIGHTIMOUT_CLKHIGHTIMOUT_S) &
|
|
PMBUS_PMBTIMHIGHTIMOUT_CLKHIGHTIMOUT_M);
|
|
HWREG(base + PMBUS_O_PMBTIMBIDLE) =
|
|
((busIdle << PMBUS_PMBTIMBIDLE_BUSIDLE_S) &
|
|
PMBUS_PMBTIMBIDLE_BUSIDLE_M);
|
|
HWREG(base + PMBUS_O_PMBTIMSTSETUP) =
|
|
((setupTime << PMBUS_PMBTIMSTSETUP_TSU_STA_S) &
|
|
PMBUS_PMBTIMSTSETUP_TSU_STA_M);
|
|
}
|
|
|
|
//
|
|
// Restore the interrupt status
|
|
//
|
|
HWREG(base + PMBUS_O_PMBINTM) = interruptState;
|
|
EDIS;
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// End of file
|
|
//
|