Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix adc #124

Merged
merged 3 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/psoc6/feature_list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Table :ref:`configuration details <table_mpy_configuration>` below lists specifi
| | |
| | Constants not yet implemented : *WLAN_WAKE*, *PIN_WAKE*, *RTC_WAKE*, *IDLE*, *SLEEP*, *DEEPSLEEP*. |
| | |
| | Submodules/classes not yet implemented: *ADC*, *bitstream*, *mem*, *Signal*, *SD*, *SDCard*, *SoftSPI*, *SPI*, |
| | Submodules/classes not yet implemented: *bitstream*, *mem*, *Signal*, *SD*, *SDCard*, *SoftSPI*, *SPI*, |
| | *Timer*, *UART*, *WDT*. |
+-----------------+----------------------------------------------------------------------------------------------------------------------+
| machine.Pin | Functions not yet implemented: *drive()*, *mode()*, *pull()*. |
Expand Down
13 changes: 8 additions & 5 deletions docs/psoc6/quickref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -619,10 +619,6 @@ PSoC6 supports only 1 12-bit SAR ADC with the following channel to pin mapping a

..
TODO: This is only applicable to the CY8CPROTO-062-4343W. This does not belong here.
TODO: Define approach on how the user gets to know the pinout diagram, alternate function of each board
- From board manual?
- From datasheet?
- To create a pinout diagram?

.. note::
Arbitrary connection of ADC channels to GPIO is not supported. Specifying a pin that is not connected to this block,
Expand All @@ -633,10 +629,17 @@ To use the APIs:

from machine import ADCBlock

adcBlock = ADCBlock(0, bits=12) # create an ADCBlock 0 object
adcBlock = ADCBlock(0, bits=11) # create an ADCBlock 0 object
adc = adcBlock.connect(0, "P10_0") # connect channel 0 to pin P10_0
val = adc.read_uv() # read an analog value in micro volts

.. note::
The ADC block supports only 11 bits resolution. If bits are not passed, by default 11 bits is considered.

.. warning::
When the input to ADC pin is connected to GND, it may not return value 0 as digitized output. This is a known issue and
needs fix in low-level API's.

I2S bus
-------

Expand Down
12 changes: 11 additions & 1 deletion ports/psoc6/machine_adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ machine_adc_obj_t *machine_adc_make_init(uint32_t sampling_time, mp_obj_t pin_na
return adc;
}

// Helper function to get resolution
uint8_t adc_get_resolution(machine_adc_obj_t *adc) {
printf("ADC bits: %d", adc->block->bits);
return adc->block->bits;
}

// machine_adc_print()
STATIC void machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
Expand Down Expand Up @@ -111,7 +117,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_block_obj, machine_adc_block);
// read_u16()
STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) {
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
return MP_OBJ_NEW_SMALL_INT(cyhal_adc_read_u16(&(self->adc_chan_obj)));
int32_t adc_raw_result = cyhal_adc_read(&(self->adc_chan_obj));
mp_int_t bits = (mp_int_t)adc_get_resolution(self);
mp_uint_t u16 = adc_raw_result << (16 - bits);
return MP_OBJ_NEW_SMALL_INT(u16);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16);

Expand All @@ -122,6 +131,7 @@ STATIC mp_obj_t machine_adc_read_uv(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_uv_obj, machine_adc_read_uv);


STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_adc_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) },
Expand Down
18 changes: 16 additions & 2 deletions ports/psoc6/machine_adcblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@ static void _adc_block_obj_init(machine_adcblock_obj_t *adc_block, uint16_t adc_
if (status != CY_RSLT_SUCCESS) {
mp_raise_TypeError(MP_ERROR_TEXT("ADC Initialization failed!"));
}
const cyhal_adc_config_t adc_config = {
.continuous_scanning = false, // Continuous Scanning is disabled
.average_count = 1, // Average count disabled
.vref = CYHAL_ADC_REF_VDDA, // VREF for Single ended channel set to VDDA
.vneg = CYHAL_ADC_VNEG_VSSA, // VNEG for Single ended channel set to VSSA
.resolution = 12u, // 12-bit resolution
.ext_vref = NC, // No connection
.bypass_pin = NC
}; // No connection

status = cyhal_adc_configure(&(adc_block->adc_obj), &adc_config);
if (status != CY_RSLT_SUCCESS) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("ADC configuration update failed. Error: %ld ! \n"), status);
}

adc_block->id = adc_block_id;
adc_block->bits = bits;
Expand Down Expand Up @@ -230,7 +244,7 @@ STATIC mp_obj_t machine_adcblock_make_new(const mp_obj_type_t *type, size_t n_po
mp_arg_parse_all(n_pos_args - 1, all_args + 1, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint8_t bits = args[ARG_bits].u_int;
if (bits != DEFAULT_ADC_BITS) {
mp_raise_TypeError(MP_ERROR_TEXT("Invalid bits. Current ADC configuration supports only 12 bits resolution!"));
mp_raise_TypeError(MP_ERROR_TEXT("Invalid bits. Current ADC configuration supports only 11 bits resolution!"));
}

return MP_OBJ_FROM_PTR(machine_adcblock_make_init(adc_id, bits));
Expand Down Expand Up @@ -285,7 +299,7 @@ STATIC mp_obj_t machine_adcblock_connect(size_t n_pos_args, const mp_obj_t *pos_
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_adcblock_connect_obj, 2, machine_adcblock_connect);

STATIC const mp_rom_map_elem_t machine_adcblock_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_adcblock_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_adcblock_deinit_obj)},
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&machine_adcblock_connect_obj) },
};
STATIC MP_DEFINE_CONST_DICT(machine_adcblock_locals_dict, machine_adcblock_locals_dict_table);
Expand Down
115 changes: 99 additions & 16 deletions tests/psoc6/hw_ext/adc.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,115 @@
### ADC Functional test
""" Setup description:
Connect 3.3V input to adc_pin0 and 0V input to adc_pin1. With the setup done, run the test.

*Known issue: The max output voltage currently is ~2.3V for 3.3V input.
Construct a basic voltage divider with 120 ohms each resistor. Supply the ends with 3.3V and GND.
Available voltage values are then - 3.3V, ~1.7V, 0V.
Pin connections:
Voltage Divider circuit On Target Board
3.3V end adc_pin_max
Mid point adc_pin_mid
GND end adc_pin_gnd
*Known issue: When connected to GND, you may not get exact 0V and this may vary board to board.
"""
import os
import time
from machine import PWM, ADC
from machine import ADC, ADCBlock

# Allocate pin based on board
machine = os.uname().machine
if "CY8CPROTO-062-4343W" in machine:
adc_pin0 = "P10_0"
adc_pin1 = "P10_1"
# TODO: Refactor test for more functionality coverage
adc_pin_gnd = "P10_1"
adc_pin_mid = "P10_3"
adc_pin_max = "P10_0"
adc_wrong_pin_name = "P13_7"
# Enable after DUT setup
print("SKIP")
raise SystemExit
elif "CY8CPROTO-063-BLE" in machine:
adc_pin0 = "P10_0"
adc_pin1 = "P10_1"
# TODO: Refactor test for more functionality coverage
adc_pin_gnd = "P10_1"
adc_pin_mid = "P10_3"
adc_pin_max = "P10_0"
adc_wrong_pin_name = "P13_7"
print("SKIP")
raise SystemExit

adc0 = ADC(adc_pin0, sample_ns=1000)
adc1 = ADC(adc_pin1, sample_ns=1000)
# 0.35V
tolerance_uv = 350000

tolerance_raw = 4000

block = None


def validate_adc_uv_value(adc_pin, exp_volt, act_volt):
print(
"\nExpected voltage - ",
exp_volt,
"(uV) on pin ",
adc_pin,
"is approx same as obtained voltage(uV): ",
(exp_volt - tolerance_uv) < act_volt < (exp_volt + tolerance_uv),
)


def validate_adc_raw_value(adc_pin, exp_volt, act_volt):
print(
"\nExpected voltage - ",
exp_volt,
"(raw) on pin ",
adc_pin,
"is approx same as obtained voltage(raw): ",
(exp_volt - tolerance_raw) < act_volt < (exp_volt + tolerance_raw),
)


# Exception should be raised
try:
adc = ADC(adc_wrong_pin_name)
except:
print("Invalid ADC Pin\n")

adc0 = ADC(adc_pin_gnd, sample_ns=1000)
print(adc0)

block = ADCBlock(0, bits=12)
# ADCBlock.connect(channel)
adc1 = block.connect(3)
print("\nADCBlock.connect(channel): ", adc1)
block.deinit()
print("ADCBlock.deinit(): ", block)

# ADCBlock.connect(source)
block = ADCBlock(0, bits=12)
adc1 = block.connect(adc_pin_mid)
print("ADCBlock.connect(source): ", adc1)
block.deinit()
print("ADCBlock.deinit(): ", block)

# ADCBlock.connect(channel,source)
block = ADCBlock(0, bits=12)
adc1 = block.connect(3, adc_pin_mid)
print("ADCBlock.connect(channel,source)", adc1)

adc2 = ADC(adc_pin_max, sample_ns=1000)
print("\n", adc2)

adc0_value_uv = adc0.read_uv()
validate_adc_uv_value(adc_pin_gnd, 0, adc0_value_uv)
adc0_value_raw = adc0.read_u16()
validate_adc_raw_value(adc_pin_gnd, 0, adc0_value_raw)

adc1_value_uv = adc1.read_uv()
validate_adc_uv_value(adc_pin_mid, 1650000, adc1_value_uv)
adc1_value_raw = adc1.read_u16()
validate_adc_raw_value(adc_pin_mid, 16385, adc1_value_raw)

adc2_value_uv = adc2.read_uv()
validate_adc_uv_value(adc_pin_max, 3300000, adc2_value_uv)
adc2_value_raw = adc2.read_u16()
validate_adc_raw_value(adc_pin_max, 32767, adc2_value_raw)

print("Voltage (in microvolts) on pin", adc_pin0, "is max: ", adc0.read_uv() > 1000000)
print("Voltage (raw count) on pin", adc_pin0, "is max: ", adc0.read_u16() > 500)
print("Voltage (in microvolts) on pin", adc_pin1, "is max: ", adc1.read_uv() < 1000000)
print("Voltage (raw count) on pin", adc_pin1, "is max: ", adc1.read_u16() < 500)
adc0.deinit()
print("\n", adc0)
adc1.deinit()
print(adc1)
adc2.deinit()
print(adc2)
31 changes: 27 additions & 4 deletions tests/psoc6/hw_ext/adc.py.exp
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
Voltage (in microvolts) on pin P10_0 is max: True
Voltage (raw count) on pin P10_0 is max: True
Voltage (in microvolts) on pin P10_1 is max: True
Voltage (raw count) on pin P10_1 is max: True
Invalid ADC Pin

<ADC Pin=81, ADCBlock_id=0, sampling_time_ns=1000>

ADCBlock.connect(channel): <ADC Pin=83, ADCBlock_id=0, sampling_time_ns=1000>
ADCBlock.deinit(): ADCBlock(0, bits=12)
ADCBlock.connect(source): <ADC Pin=83, ADCBlock_id=0, sampling_time_ns=1000>
ADCBlock.deinit(): ADCBlock(0, bits=12)
ADCBlock.connect(channel,source) <ADC Pin=83, ADCBlock_id=0, sampling_time_ns=1000>

<ADC Pin=80, ADCBlock_id=0, sampling_time_ns=1000>

Expected voltage - 0 (uV) on pin P10_1 is approx same as obtained voltage(uV): True

Expected voltage - 0 (raw) on pin P10_1 is approx same as obtained voltage(raw): True

Expected voltage - 1650000 (uV) on pin P10_3 is approx same as obtained voltage(uV): True

Expected voltage - 16385 (raw) on pin P10_3 is approx same as obtained voltage(raw): True

Expected voltage - 3300000 (uV) on pin P10_0 is approx same as obtained voltage(uV): True

Expected voltage - 32767 (raw) on pin P10_0 is approx same as obtained voltage(raw): True

<ADC Pin=81, ADCBlock_id=0, sampling_time_ns=1000>
<ADC Pin=83, ADCBlock_id=0, sampling_time_ns=1000>
<ADC Pin=80, ADCBlock_id=0, sampling_time_ns=1000>
Loading