cancel
Showing results for 
Search instead for 
Did you mean: 

PSoC 6 MCU

Jdo300
New Contributor II

I found a code example from the PSoC4 that shows how to switch ADC voltage references to measure and calculate the battery voltage going into the PSoC module.  I need to do the same thing but using the PSoC6 rather than the PSoC4. However, it looks like the code to actually switch the ADC voltage references is different in the PSoC6 that 4. Here is the function I extracted and adapted to the PSoC6 version so far:

// Reads the current supply voltage to determine battery level
byte BAS_ReadBatteryLevel()
{
int16 adcResult;
int32 mvolts;
uint32 sarControlReg;
uint8 batteryLevel;

/* Set the reference to 1.024V and enable reference bypass */
sarControlReg = ADC_SAR_CTRL_REG & ~ADC_VREF_MASK;
ADC_SAR_CTRL_REG = sarControlReg | ADC_VREF_INTERNAL1024BYPASSED;

/* 25 ms delay for reference capacitor to charge */
CyDelay(25u);

/* Set the reference to VDD and disable reference bypass */
sarControlReg = ADC_SAR_CTRL_REG & ~ADC_VREF_MASK;
ADC_SAR_CTRL_REG = sarControlReg | ADC_VREF_VDDA;

/* Perform a measurement. Store this value in Vref. */
CyDelay(1u);
ADC_StartConvert();
ADC_IsEndConversion(ADC_WAIT_FOR_RESULT);

/* Set the reference to 1.024V and enable reference bypass */
sarControlReg = ADC_SAR_CTRL_REG & ~ADC_VREF_MASK;
ADC_SAR_CTRL_REG = sarControlReg | ADC_VREF_INTERNAL1024BYPASSED;

adcResult = ADC_GetResult16(ADC_BATTERY_CHANNEL);

/* Calculate input voltage by using ratio of ADC counts from reference
* and ADC Full Scale counts.
*/
mvolts = (1024 * 2048) / adcResult;

/* Convert battery level voltage to percentage using linear approximation
* divided to two sections according to typical performance of
* CR2033 battery specification:
* 3V - 100%
* 2.8V - 29%
* 2.0V - 0%
*/
if(mvolts < MEASURE_BATTERY_MIN)
{
batteryLevel = 0;
}
else if(mvolts < MEASURE_BATTERY_MID)
{
batteryLevel = (mvolts - MEASURE_BATTERY_MIN) * MEASURE_BATTERY_MID_PERCENT /
(MEASURE_BATTERY_MID - MEASURE_BATTERY_MIN);
}
else if(mvolts < MEASURE_BATTERY_MAX)
{
batteryLevel = MEASURE_BATTERY_MID_PERCENT +
(mvolts - MEASURE_BATTERY_MID) * (100 - MEASURE_BATTERY_MID_PERCENT) /
(MEASURE_BATTERY_MAX - MEASURE_BATTERY_MID);
}
else
{
batteryLevel = CY_BLE_BAS_MAX_BATTERY_LEVEL_VALUE;
}

return batteryLevel;
}

The constants ADC_SAR_CTRL_REG, ADC_VREF_MASK, and ADC_VREF_INTERNAL1024BYPASSED don't appear to exist on the PSoC6 version of the ADC. Here's my schematic setup for the ADC (I tried to make it as close as possible to the PSoC4 version settings):

Jdo300_0-1618242931932.png

Jdo300_1-1618242980047.png

Jdo300_2-1618243005410.png

 

 

 

Jdo300_3-1618243056609.png

Could someone provide some guidance on how I can adapt this code to work on the PSoC6? I'm using the CYBLE-416045-02 BLE Module on a custom PCB running off of a 3V CR2032 battery.

0 Likes
2 Replies
Jdo300
New Contributor II

Update:

I found an article at this link here explaining what the ADC registers are for changing the VREF Value. It wasn't clear if this actually works for the PSoC6 or not but I thought I'd give it a try and updated my function to follow the same logic as outlined in the example:

#define ADC_VREF_MASK (0x000000F0Lu)
#define ADC_VREF_INTERNAL1024BYPASSED (0x000000C0Lu)
#define ADC_VREF_VDDA (0x000000F0Lu)
#define ADC_BATTERY_CHANNEL (0x00u)

// Reads the current supply voltage to determine battery level
byte BAS_ReadBatteryLevel()
{
int16 adcResult;
int32 mvolts;
uint32 sarControlReg;
uint8 batteryLevel;

/* Set the reference to 1.024V and enable reference bypass */
sarControlReg = CY_GET_REG32(CYREG_SAR_CTRL) & ~ADC_VREF_MASK;
CY_SET_REG32(CYREG_SAR_CTRL, sarControlReg | ADC_VREF_INTERNAL1024BYPASSED);

/* 100 ms delay for reference capacitor to charge */
CyDelay(100u);

/* Set the reference to VDD and disable reference bypass */
sarControlReg = CY_GET_REG32(CYREG_SAR_CTRL) & ~ADC_VREF_MASK;
CY_SET_REG32(CYREG_SAR_CTRL, sarControlReg | ADC_VREF_VDDA);

/* Perform a measurement. Store this value in Vref. */
CyDelay(1u);
ADC_StartConvert();
ADC_IsEndConversion(CY_SAR_WAIT_FOR_RESULT);

/* Set the reference to 1.024V and enable reference bypass */
sarControlReg = CY_GET_REG32(CYREG_SAR_CTRL) & ~ADC_VREF_MASK;
CY_SET_REG32(CYREG_SAR_CTRL, sarControlReg | ADC_VREF_INTERNAL1024BYPASSED);

adcResult = ADC_GetResult16(ADC_BATTERY_CHANNEL);

/* Calculate input voltage by using ratio of ADC counts from reference
* and ADC Full Scale counts.
*/
mvolts = (1024 * 2048) / adcResult;

/* Convert battery level voltage to percentage using linear approximation
* divided to two sections according to typical performance of
* CR2033 battery specification:
* 3V - 100%
* 2.8V - 29%
* 2.0V - 0%
*/
if(mvolts < MEASURE_BATTERY_MIN)
{
batteryLevel = 0;
}
else if(mvolts < MEASURE_BATTERY_MID)
{
batteryLevel = (mvolts - MEASURE_BATTERY_MIN) * MEASURE_BATTERY_MID_PERCENT /
(MEASURE_BATTERY_MID - MEASURE_BATTERY_MIN);
}
else if(mvolts < MEASURE_BATTERY_MAX)
{
batteryLevel = MEASURE_BATTERY_MID_PERCENT +
(mvolts - MEASURE_BATTERY_MID) * (100 - MEASURE_BATTERY_MID_PERCENT) /
(MEASURE_BATTERY_MAX - MEASURE_BATTERY_MID);
}
else
{
batteryLevel = CY_BLE_BAS_MAX_BATTERY_LEVEL_VALUE;
}

return batteryLevel;
}

Now, my program compiles but when I run the code, the ADC_GetResult16() function always returns zero. Any idea what could is wrong here?

0 Likes
Vasanth
Moderator
Moderator

Hi,

The register TRM for PSoC6 has information on the ADC registers to be set to change the Vref and the values are same.  First to confirm your hardware configuration, did you connect the VREF of the PSoC to ADC input pin in the hardware ?

 

Additionally I could see you changing the source again before storing the result after the conversion. Why is that ?

Vasanth_0-1618391470857.png

 

Best Regards,
Vasanth

0 Likes
Top labels