Psoc 6 AMux ADC

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Sun08
Level 2
Level 2
First like received 10 replies posted 10 sign-ins

Hello, I'm a beginner in Microcontroller, especially Psoc. I want to build a AMux Seq to select channel for ADC further measuring Voltage. But I cannot build the application. Can anybody tell me where is the Problem?

($XYY{{[FY[OA27_I95Q(%D.png

0 Likes
13 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

@Sun08 ,

Welcome to the PSoC.

Sadly you have not given enough detail about what errors you are receiving.   I see the error message in your picture but it isn't enough to infer the issue.

I've looked at your TopDesign schematic the only problem I see is that your sensors and your reference resistor has no power source to provide current.  This issue would not prevent you from a good build since the external components and external wiring is not checked or compiled by PSoC Creator.  (External components and wiring are there for the engineer's reference.)

As a separate issue, if you tell us what you are using for the sensors, we can advice as to good design practices.

The easiest way we can help on the build issue is for you to archive your project and attach it to this post.

This way we can reproduce the issues you are seeing.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Thank you so much for your reply. Honestly it’s been a tough time learning this. All I could do is downloading some code examples to get the idea of microcontroller design… Anyway, I set the pin5 as analog input and digital output at the same time. So I thought I didn’t have to add a power source, by just using the supply of ADC. But I don’t know, I don’t even know how to add a external power supply… 
My final task should be coming up with a special insole with 16 pressure sensors integrated to monitor the situation of feet. So maybe the first thing for me is to read out the resists changes resulting in voltage. Later I need some design in UART, BLE, I2C…

I’m sorry I just came out. It’d be nice if you could check the project for me to see what’s really going on. It’s just I have to send you the project a little later. 
Anyway, your reply means a lot for me. I’m just about to give up. LOL

0 Likes

@Sun08 ,

I'm glad you are patient and still pursuing and answer.  I think we can help you.

It was not clear in your TopDesign that Pin_5 was acting as a Digital_Output.  This is allowed.  However, you do have to watch out how much current is required by all loads connected to this power source.  Assume the maximum total current is 4mA.

I can help further with your sensor front end design.  I do need some information to make good recommendations.  

  • What PSoC6 part number are you using?
  • What is the minimum and maximum resistance value of the sensors?  They appear to be pressure-to-resistance sensors.
Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.

Hello, thank you a lot for your reply. And sorry for replying late... I'm using Psoc 6 CY8CKIT-062-BLE. For now I'm just trying to figure out how to design the whole project step by step, I guess I'll just use sensors like 10KΩ for now. The changes of resistance should be no more than ±2 KΩ. I have some information about the sensors but I'm not very sure that I will use that kind of sensor. At last it's gonna be 16 Sensors integrated on one patch. For now I'm thinking of realizing that on breadboard, putting some ordinary resistors on breadboard first. I think probably it's basically the same when I finally use the sensors in the same scale as resistors I'm using.

BTW, I'm sorry but I don't know why maximum total current is important. Is it because ADC has its specific current limit?

The problem project is in attachment. Thank you for your time checking on it again!

0 Likes
lock attach
Attachments are accessible only for community members.

@Sun08 ,

I've modified your circuit to handle 16 (or more) sensors.  See attachment.

The major issue with your design is one end of each sensor goes into the Analog pin then into the AMux.   In effect, there is no current flow through the sensor. Therefore a sensor reading is useless.   In your design you need to flow the same current through the 10K reference resistor and then through the sensor.

My design turns on one sensor to GND at a time.   Therefore you can read the voltage across the reference resistor and the sensor to GND.   You can then compute the resistance of the sensor with very good accuracy.

You will also see that I use a 2-input Scanning ADC.  The GND_1 and GND_2 are used to switch the sensor to GND ONE-AT-A-TIME.

Len_CONSULTRON_0-1690140856217.png


BTW, I'm sorry but I don't know why maximum total current is important. Is it because ADC has its specific current limit?

 

 The GPIO pin as an output is capable of 8mA drive current.  If you turn only one sensor, then your maximum current draw = 3.3V / (10K + 0K) = 0.3mA.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Thank you very much for your patient help! I got the idea of your design now. I will try to do the coding part tomorrow. Hope I can work this out.;)

0 Likes

Hello, can I ask you, how to manage all GND pins in the same port, so that I can use 'for loop' to control its on and off? I noticed you put the 16 pins in 2 different ports, and I put all pins together in one port but they still shares the different ports.

Sun08_0-1690197806581.png

 

0 Likes
lock attach
Attachments are accessible only for community members.

@Sun08 ,

Attached is a new project with your requested information.

I've also have converted the TopDesign to include a 16-pin component instead of two 8-pin output components.

On the PSoC5 and PSoC3 you can only allocate a maximum of 8 pins on a port.  This is because there is only a maximum of 8 pins to a port (ie. Px[0] to Px[7]).

With the PSoC6 it uses a PDL structure.  With it you can take ANY GPIO on any physical port  (still limited to 8 per port) and allocate to a 'logical' port,   This allows you to address any pin logically to a 'port and exceed 8.

In my attached project, I have not tested it.  However, it should give you a good start on how to accomplish your goal.

Len_CONSULTRON_0-1690220438655.png

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.

@Sun08 ,

I've looked at your latest code changes.   There is quite a few things wrong with the coding in main().  

I've redesigned my previous design to get rid of the pin supplying ~3.3V and is using an IDAC7 set to 100uA.

Len_CONSULTRON_0-1690398452685.png

I also placed the 10K reference resistor on the last of 17 sensor inputs.  I use this resistor as a measurement compensation for the other readings.   

I tested this on a CY8CKIT-062-BLE.   I'm getting about 12% or better accuracy on the resistance measurements.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Hello! Thank you so much for your patience! I got your idea now. Sorry I don’t have a laptop by hand now to try this out. I think I will try this tomorrow. 
BTW, you were saying that you have already checked my latest code. Do you mean the project I just posted in the community? If so, could you shortly explain where is the problem? Cuz from my side I really cannot tell where I did it wrong. The ADC kept reading the same sensor…

And I also tried your last version project. I don’t know why ‘printf’ does not work. I noticed you haven’t included “project.h” in studio.h and added UART_HW. But in ‘main’ it still says the ‘printf’ functionality cannot be used. I’m sorry I forgot the exact error sentence…:(

0 Likes

@Sun08 ,

Alright you asked.

Len_CONSULTRON_0-1690407841714.png

The GND pin port was set to '0' (LOW) as the initial value.  It is better to set to '1' (HIGH) which is the Sensor pin OFF setting.

Here is the code you supplied in main.c

/* ========================================
 *
 * Copyright YOUR COMPANY, THE YEAR
 * All Rights Reserved
 * UNPUBLISHED, LICENSED SOFTWARE.
 *
 * CONFIDENTIAL AND PROPRIETARY INFORMATION
 * WHICH IS THE PROPERTY OF your company.
 *
 * ========================================
*/
#include "project.h"
#include <stdio.h>

static void calculate_resistance(uint8_t count);

#define NUM_PINS 16
#define SENSOR_ARRAY_LENGTH (16UL)


uint8_t Sensor_array_message[SENSOR_ARRAY_LENGTH];

GPIO_PRT_Type* Sensor_Ports[SENSOR_ARRAY_LENGTH] = {
    GND_0_PORT, GND_1_PORT, GND_2_PORT, GND_3_PORT, GND_4_PORT, GND_5_PORT, GND_6_PORT, GND_7_PORT,
    GND_8_PORT, GND_9_PORT, GND_10_PORT, GND_11_PORT, GND_12_PORT, GND_13_PORT, GND_14_PORT, GND_15_PORT
};

const uint8_t Sensor_Num[SENSOR_ARRAY_LENGTH] = {
    GND_0_NUM, GND_1_NUM, GND_2_NUM, GND_3_NUM, GND_4_NUM, GND_5_NUM, GND_6_NUM, GND_7_NUM,
    GND_8_NUM, GND_9_NUM, GND_10_NUM, GND_11_NUM, GND_12_NUM, GND_13_NUM, GND_14_NUM, GND_15_NUM
};

int main(void)
{
    __enable_irq(); /* Enable global interrupts. */
    
    UART_Start();
    ADC_Start();
    Cy_SAR_StartConvert(SAR, CY_SAR_START_CONVERT_CONTINUOUS);
    Cy_GPIO_Write(Sensor_pwr_PORT, Sensor_pwr_NUM, 1);
    uint8_t count = 0;
    
    
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    for(;;)
    {
        calculate_resistance(count);
        count++;
        
        if(count > 15)
        {
            printf("Sensor resistances are:");
            for(int i=0; i<16; i++){
                printf("%d", Sensor_array_message[i]);
            }
            printf("\n");
            count = 0;
        }
        
        /* Place your application code here. */
    }
}

static void calculate_resistance(uint8_t count)
{
    float Vref, Vses;
    int32_t countreference1, countreference2;
    float Rses;
    
    Cy_GPIO_Write(Sensor_Ports[count], Sensor_Num[count], 1);
    countreference1 = Cy_SAR_GetResult32(SAR, 0);
    countreference2 = Cy_SAR_GetResult32(SAR, 1);
    Vref = Cy_SAR_CountsTo_Volts(SAR, 0, countreference1);
    Vses = Cy_SAR_CountsTo_Volts(SAR, 1, countreference2);
    Rses = 10 * Vref / Vses;
    Sensor_array_message[count] = Rses;
        
    Cy_GPIO_Write(Sensor_Ports[count], Sensor_Num[count], 0);

}

/* [] END OF FILE */

Most of the issues are in calculate_resistance().

First Issue  - You have the ON and OFF states of the pin reversed.

The first Cy_GPIO_Write(Sensor_Ports[count], Sensor_Num[count], 1); with '1' turns OFF the sensor you are trying to measure.

The second Cy_GPIO_Write(Sensor_Ports[count], Sensor_Num[count], 0); with '0' turns ON the sensor you are trying to measure.

Once all the sensor are cycled through, ALL the sensor pins are left ON.

Second Issue - You are not waiting for the end of the conversion

You need to wait for the end of a conversion before you perform a Cy_SAR_GetResult32(). Just reading the value before the conversion is done, the value will be incomplete and m be wrong.  This issue is compounded when you are averaging 256 samples.

Third Issue - You are using the ADC in Continuous Conversion mode

The ADC in Continuous conversion mode will cycle through all the channels configured in the ADC.   You are switching the active sensor sometime potentially in the middle of a reading on channel 1.  Therefore you will probably read the value of two sensors on channel 1 giving you a wrong reading.

Recommendation:  In the calculate_resistance() function switch the desired sensor ON and then start the conversion using Cy_SAR_StartConvert(SAR, CY_SAR_START_SINGLE_SHOT);

Next wait for the conversion to end before reading the channel's value.

Fourth Issue - You are pushing a float value into a array of uint8_t

You are forcing a float 'Rses' into a uint8_t array Sensor_array_message[].

You don't have a type cast so therefore it is not guaranteed that the implicit cast occurs.

Fifth Issue - The Rses value from float to uint8_t is too small

A uint8_t can only handle a value of 256 max.   Your resistors range from 0 to 20K.   At best the value of Rses converted to uint8_t will value wrap (ie value % 256).

Sixth Issue - Resistance accuracy

I assume with the following line:

Rses = 10 * Vref / Vses;

That you are only interested in resistance value measurements in 10's of K's.

If you want more resolution, you need to substitute '10000' in place of the '10' in the formula above.

 

 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Hello, I tried your codes, but the measured values are all 10000. I'm thinking if it's because the way you calculate resistance here. The Rses you calculated here is actually Rref. And when I changed its way calculating to just Rses = (uint32_t) ((float) Vses_uV/ (float)IDAC_SET_uA). The results are all 11930.

Sun08_0-1690454202282.png

Sun08_1-1690454368232.png

 

 

0 Likes

And I changed my codes by your advice, it still doesn't work...

 

/* ========================================
*
* Copyright YOUR COMPANY, THE YEAR
* All Rights Reserved
* UNPUBLISHED, LICENSED SOFTWARE.
*
* CONFIDENTIAL AND PROPRIETARY INFORMATION
* WHICH IS THE PROPERTY OF your company.
*
* ========================================
*/
#include "project.h"
#include <stdio.h>

static void calculate_resistance(uint8_t count);
static void Initial_all_GND(void);

#define NUM_PINS 16
#define SENSOR_ARRAY_LENGTH (16UL)


float Sensor_array_message[SENSOR_ARRAY_LENGTH];

GPIO_PRT_Type* Sensor_Ports[SENSOR_ARRAY_LENGTH] = {
GND_0_PORT, GND_1_PORT, GND_2_PORT, GND_3_PORT, GND_4_PORT, GND_5_PORT, GND_6_PORT, GND_7_PORT,
GND_8_PORT, GND_9_PORT, GND_10_PORT, GND_11_PORT, GND_12_PORT, GND_13_PORT, GND_14_PORT, GND_15_PORT
};

const uint8_t Sensor_Num[SENSOR_ARRAY_LENGTH] = {
GND_0_NUM, GND_1_NUM, GND_2_NUM, GND_3_NUM, GND_4_NUM, GND_5_NUM, GND_6_NUM, GND_7_NUM,
GND_8_NUM, GND_9_NUM, GND_10_NUM, GND_11_NUM, GND_12_NUM, GND_13_NUM, GND_14_NUM, GND_15_NUM
};

int main(void)
{
__enable_irq(); /* Enable global interrupts. */

UART_Start();
ADC_Start();
// Cy_SAR_StartConvert(SAR, CY_SAR_START_CONVERT_CONTINUOUS);
Cy_GPIO_Write(Sensor_pwr_PORT, Sensor_pwr_NUM, 1);
uint8_t count = 0;

/* Place your initialization/startup code here (e.g. MyInst_Start()) */

for(;;)
{
Initial_all_GND();

calculate_resistance(count);
count++;

if(count > 15)
{
printf("Sensor resistances are:");
for(int i=0; i<16; i++){
printf("%fK ohm ", Sensor_array_message[i]);
}
printf("\n\r");
count = 0;
CyDelay(1000);
}

/* Place your application code here. */
}
}


static void Initial_all_GND(void)
{
for(int i=0; i<16; i++){
Cy_GPIO_Write(Sensor_Ports[i], Sensor_Num[i], 1);
}

}


static void calculate_resistance(uint8_t count)
{
float Vref, Vses;
int32_t countreference1, countreference2;
float Rses;

Cy_GPIO_Write(Sensor_Ports[count], Sensor_Num[count], 0);

Cy_SAR_StartConvert(SAR, CY_SAR_START_CONVERT_SINGLE_SHOT);
Cy_SAR_IsEndConversion(SAR, CY_SAR_WAIT_FOR_RESULT);
// while(ADC_IsEndConversion(CY_SAR_WAIT_FOR_RESULT));
// ADC_StopConvert();


countreference1 = Cy_SAR_GetResult32(SAR, 0);
countreference2 = Cy_SAR_GetResult32(SAR, 1);

Vref = Cy_SAR_CountsTo_uVolts(SAR, 0, countreference1);
Vses = Cy_SAR_CountsTo_uVolts(SAR, 1, countreference2);

// Vref = ADC_GetResult16(0);
// Vses = ADC_GetResult16(1);

Rses = 10 * (Vses / Vref);
Sensor_array_message[count] = Rses;

Cy_GPIO_Write(Sensor_Ports[count], Sensor_Num[count], 1);

}

/* [] END OF FILE */

0 Likes