I can see in Segger Embedded Studio v4.52 under the Build Tab, there are two methods to build the project.
1- Build > Build zephyr/zephyr.elf
2- Build > Build solution
What is the difference between the two methods?
Kind regards
I can see in Segger Embedded Studio v4.52 under the Build Tab, there are two methods to build the project.
1- Build > Build zephyr/zephyr.elf
2- Build > Build solution
What is the difference between the two methods?
Kind regards
Hi again!
So, first of all, to answer your questions about SPI:
You are right, I did not catch that part. I have sent a message to the Nordic developer that has written this, but since they are based in LA I won't have an answer on this until tomorrow.
I just received an answer about this.
"An index representing the peripheral’s chip select line number. (If there is no chip select line, 0 is used.)"
The spi1 node has a cs-gpios property, which means that the unit addresses for node a and b (0 and 1 respectively) are indexes into the cs-gpios array (an index representing the peripheral's chip select line number). The spi1 node has no cs-gpios, so node c has no chip select configured in the device tree, and therefore its unit address is left at 0 (if there is no chip select line, 0 is used).
In all your overlay examples you're still instantiating the ADC peripheral, which we don't want to do.
This is the template you want to follow:
/ { n: node { compatible = " "; io-channels = <&adc 4>; label = "AIN_0"; }; };
The forward slash indicates the root node and is very important to include.
To include multiple ADC io-channels, just refer to the adc-node each time like this (not &adc5 and &adc7):
io-channels = <&adc 26>, <&adc 28>;
and if you want to use a different compatible property for the two nodes, you need to create two separate nodes like this:
/ { n: node_a { compatible = " "; io-channels = <&adc 26>; label = "AIN_5"; }; n: node_b { compatible = " "; io-channels = <&adc 28>; label = "AIN_7"; }; };
For you question about voltage-divider
The lower leg is not a resistor, but the other one is a resistor? Or are you using a capacitive divider where both elements are capacitors?
For your binding question, yes this is the correct way to do it, using the label you defined in the node.
adc_dev_5 = device_get_binding("AIN_5");
adc_dev_7 = device_get_binding("AIN_7");
To do the binding for the two analog inputs, this is how to do it for AIN_5 and AIN_7 respectively.
device_get_binding(DT_IO_CHANNELS_LABEL_BY_IDX(DT_NODELABEL(n),0))
device_get_binding(DT_IO_CHANNELS_LABEL_BY_IDX(DT_NODELABEL(n),1))
Best regards,
Heidi
If I include in main.c
#include <hal/nrf_saadc.h>
and use this overlay file
&pwm0 {
ch0-pin = < 29 >;
};
/ {
n: node {
compatible = "voltage-divider";
io-channels = <&adc 4>;
label = "AIN_0";
};
};
then I get a different error,
devicetree error: 'output-ohms' is marked as required in 'properties:' in C:/Zypher/v1.3.0/zephyr/dts/bindings\adc\voltage-divider.yaml, but does not appear in <Node /node in 'nrf5340pdk_nrf5340_cpuapp.dts.pre.tmp'>
This suggests I need to add these two lines to the device tree fragment in the overlay file
output-ohms = <???>;
full-ohms = <(??? + ???)>;
But I am not sure if the "voltage-divider" works with an R-C circuit?
Finally, get_binding() does not bind AIN_0, it can only bind ADC_0.
Are you sure the label line can have something other than ADC_0?
Maybe I Should make changes to the source code (the light intensity controller example) in main.c when I am using the overlay file ?
Kind regards
Mohamed
Good morning Heidi,
What do you mean by this? I assume you will have to change the main.c file, firstly to bind the IO-channels.
Yes, of course, to get the binding to work using the new labels with the DT_ macros.
ADC raw (LSB) conversion results: ----------------------------------------------
I used ADC on various microcontrollers before and the ADC peripherals were straight forward to use and always provided raw (LSB) a2d results. Whys is it so complicated with this SoC/zephyr?
Why can't I use the "nordic,nrf-saadc" driver since it is the native nordic adc driver?
General questions: ------------------------
1- How can I add a comment in the overlay and dts files? I added few lines with a leading # but it caused problems. Does the # need to be in a particular location on a line?
2- I sometimes see fragment of DeviceTree code containing this @... Does this mean the user has to replace the ... with a number?
Thank you.
Kind regards
Mohamed
Hi!
Let me answer these questions first:
1. In the overlay and dts files, comments are added with "// Comment" or for multiple lines "/* Comment 1 \n Comment 2 */".
The comment sign "#" is used for configuration files like prj.conf and KConfig files.
2. Yes, node-name@... means there should be some unit-address in "..." but this depends on the SoC which is why it's not included.
I'm still working on getting some more info about the ADC peripheral.
Learner said:Why can't I use the "nordic,nrf-saadc" driver since it is the native nordic adc driver?
This is what I was told by one of the developers. We can't use it because it's only made to instantiate the ADC peripheral, and that's not what this node is. I can try to find a better explanation for this.
Do you just want a way to get the raw a2d results? You can take a look at this sample code which shows how to get raw ADC data.
The light controller example that you were working with also demonstrates how to get raw ADC data from an analog input.
The reason this is complicated is that we are trying to do it through an overlay file and there is very little sample code available, as it seems this isn't the common way to do it.
Learner said:ADC raw (LSB) conversion results: ----------------------------------------------
What is this? Is this from the log file?
Best regards,
Heidi
Hi Heidi,
I may not always get the answer I am looking for but I do appreciate your efforts. A big THANK YOU.
The reason this is complicated is that we are trying to do it through an overlay file and there is very little sample code available, as it seems this isn't the common way to do it.
Yes, I did see examples using the adc peripheral but they all use the #define and DT_ macros. I thought since almost every other hardware configuration can be done via the overlay file it would be a neat way to get the adc peripheral configured in the same way. If nordic/zephyr experts think that this is not the way to go about it then it is fine but they must let users like me know as early as possible so that no time is wasted. I may have to drop the idea of using the overlay file for the adc peripheral, which is a shame because I think it is a neater way.
Do you just want a way to get the raw a2d results?
Yes, I was expecting to get raw (LSB) values that I can then process/scale in my firmware. So, the "nordic,nrf-saadc" should provide that.
This is what I was told by one of the developers. We can't use it because it's only made to instantiate the ADC peripheral, and that's not what this node is. I can try to find a better explanation for this.
Please do. I cannot believe nordic do not provide a driver for their ad peripheral...
What is this? Is this from the log file?
No, this is just me trying to make my post more readable and break it into sections to make life easier for the support staff like your good self.
Kind regards
Mohamed
Hi!
To get the raw ADC information, you don't need a device tree `[compatible]`, because this is just what the ADC driver returns. You only need this when there is external hardware-related information (like the resistance and capacitance of an RC-divider) that needs to be exposed to the code to convert a raw ADC reading into something meaningful. This is shown in the battery sample I have linked to previously.
The `[voltage-divider]` is intended to match the Linux binding with the same `[compatible]` name. I can't find a Linux compatible for "RC-divider" but if there is one try to use that instead.
Otherwise, users can create their own bindings and then use this as the `[compatible]`property. See the Zephyr Bindings documentation before you start writing it, for the file syntax and conventions, etc. Make sure to use a `[compatible]` that's namespaced to avoid conflict with other devicetree node identifiers; use something like `[companyname,rc-divider]`.
I spoke to one of the developers and he is going to try to write a binding and small sample for the HW setup you are using (the op-amp and RC-divider).
Learner said:Please do. I cannot believe nordic do not provide a driver for their ad peripheral...
Nordic definitely has a driver for the ADC peripheral, it's in zephyr/drivers/adc/adc_nrfx_saadc.c, and included in the general zephyr ADC driver here when CONFIG_ADC_NRFX_SAADC is enabled.
This driver is used in the battery sample here. This is what you will use in the main.c file, because not everything can be done in the device tree.
But we can wait for the binding and sample, and see if that helps you along!
Best regards,
Heidi
Thank you Heidi.
For now I will get rid of the overlay file and use the raw adc readings. I think this will be good enough for our application.
I am not sure what CHANNEL_INPUT adc configuration parameter. in the code fragment below does. The code has been extracted from
https://github.com/nrfconnect/sdk-zephyr/blob/master/tests/drivers/adc/adc_api/src/test_adc.c
#define ADC_1ST_CHANNEL_ID 0 Is this selecting analog input pin AIN0 i.e. port P0.04?
#define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1 It is used to set .input_positive in struct adc_channel_cfg This equates to 2 but not sure what it does. What is the difference between CHANNEL_ID and CHANNEL_INPUT?
#define ADC_2ND_CHANNEL_ID 2 Is this selecting analog input pin AIN2 i.e. port P0.06?
#define ADC_2ND_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2 It is used to set .input_positive in struct adc_channel_cfg This equates to 3 but not sure what it does. What is the difference between CHANNEL_ID and CHANNEL_INPUT?
Thank you
Kind regards
Mohamed
Thank you Heidi.
For now I will get rid of the overlay file and use the raw adc readings. I think this will be good enough for our application.
I am not sure what CHANNEL_INPUT adc configuration parameter. in the code fragment below does. The code has been extracted from
https://github.com/nrfconnect/sdk-zephyr/blob/master/tests/drivers/adc/adc_api/src/test_adc.c
#define ADC_1ST_CHANNEL_ID 0 Is this selecting analog input pin AIN0 i.e. port P0.04?
#define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1 It is used to set .input_positive in struct adc_channel_cfg This equates to 2 but not sure what it does. What is the difference between CHANNEL_ID and CHANNEL_INPUT?
#define ADC_2ND_CHANNEL_ID 2 Is this selecting analog input pin AIN2 i.e. port P0.06?
#define ADC_2ND_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2 It is used to set .input_positive in struct adc_channel_cfg This equates to 3 but not sure what it does. What is the difference between CHANNEL_ID and CHANNEL_INPUT?
Thank you
Kind regards
Mohamed
Hi!
https://github.com/pabigot/fw-nrfconnect-nrf/tree/sample/20201020a has the example in samples/myapp.
The README file has a lot of information.
This example shows how to represent analog input signals and associated hardware properties in a devicetree bindings. The described problem domain was for two analog inputs, one for an op-amp, one for an RC-divider.
There is a custom binding for the setup you described and it configures the ADC and reads the raw data. It also converts it to millivolts, but this may be useless depending on what you want to do.
________________________________________________________________________
Now onto your questions.
Learner said:#define ADC_1ST_CHANNEL_ID 0
This is just defining the first channel ID as zero and the second channel ID as 1.
Learner said:#define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1
This is defining the first channel input as analog input 1 and the second channel input as analog input 2.
The real action happens a little lower down in the code, here:
static const struct adc_channel_cfg m_1st_channel_cfg = { .gain = ADC_GAIN, .reference = ADC_REFERENCE, .acquisition_time = ADC_ACQUISITION_TIME, .channel_id = ADC_1ST_CHANNEL_ID, // 0 #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS) .input_positive = ADC_1ST_CHANNEL_INPUT, // NRF_SAADC_INPUT_AIN1 #endif };
So the descriptions of these two properties (`[channel_id]` and `[input positive]`) are explained in the definition of the adc_channel_cfg struct. I have pasted them below in cursive and then added clarifying comments for your specific case that are not in cursive but underlined.
channel_id: This value primarily identifies the channel within the ADC API - when a read request is done, the corresponding bit in the ´[channels]´ `[channels]´ field of the ´[adc_sequence]´ structure must be set to include this channel in the sampling. In the test_adc sample, this is done here or here.
For hardware that does not allow the selection of analog inputs for given channels, but rather have dedicated ones, this value also selects the physical ADC input to be used in the sampling.
Otherwise, when it is needed to explicitly select an analog input for the channel, or two inputs when the channel is a differential one, the selection is done in ´[input_positive]´ and ´[input_negative]´ fields. Since our hardware lets us explicitly select analog inputs, this is done here, to select NRF_SAADC_INPUT_AIN1.
Particular drivers indicate which one of the above two cases they support by selecting or not a special hidden Kconfig option named ADC_CONFIGURABLE_INPUTS. If this option is not selected, the macro CONFIG_ADC_CONFIGURABLE_INPUTS is not defined and consequently, the mentioned two fields are not present in this structure. This option is selected in the nrfx ADC driver here when you enable ADC_NRFX_SAADC.
While this API allows identifiers from range 0-31, particular drivers may support only a limited number of channel identifiers (dependent on the underlying hardware capabilities or configured via a dedicated Kconfig option). In our case, the nrfx ADC driver only allows 8 channels by setting ADC_NRFX_ADC_CHANNEL_COUNT to the range 1 to 8. This means channel_id has the range 0 to 7.
input_positive: Positive ADC input, This is a driver dependent value that identifies an ADC input to be associated with the channel. So, in our case, we are associating the ADC input NRF_SAADC_INPUT_AIN1 with the channel.
So the difference is that the ´[channel_id]´ is the index into the channel array (AIN1 has index 0, AIN2 has index 1 etc.) and ´[input_positive]´ (which is the channel input) is the specific analog input, so AIN1 and AIN2.
Another thing I wanted to clarify by using the custom binding of the sample as an example, is this line:
io-channels = <&adc 0>, <&adc 1>;
As you can see, the io-channels are ´[&adc 0]´ and ´[&adc 1]´ which maps the ADC peripheral to channel 0 and 1. This just maps the ADC node to the analog input of channel 0 and the analog input of channel 1, which is AIN1 and AIN2, which then maps to GPIO pin P0.04 and P0.05 on the PDK, according to this table describing the mapping of analog pins on the nRF5340 PDK.
So this mapping is a part of the hardware and isn't something the user needs to configure. The user just needs to configure the ADC node to specific channels in the range 0 to 7. So, for instance if you want to use AIN5 and AIN7 (which on the PDK is P0.07 and P0.26 respectively), you would need to define these io-channels.
io-channels = <&adc 4>, <&adc 6>;
Then due to the HW mapping of the board, these io-channels are GPIO pin 7 and GPIO pin 26.
This is something I just learned as well, which is why I haven't corrected it before.
Learner said:Is this selecting analog input pin AIN0 i.e. port P0.04?
So finally to answer this question, this line
´[#define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1]´
along with this line
´[.input_positive = ADC_1ST_CHANNEL_INPUT]´
sets the ADC input to be the analog input AIN1 (i.e GPIO pin 0.04, though this connection exists in HW and isn't something we need to configure in SW).
I hope that was clarifying. Again sorry for sometimes coming with new and different information, but I am also learning along with you.
Best regards,
Heidi
Hi Heidi,
Thank you for your answers.
So the difference is that the ´[channel_id]´ is the index into the channel array (AIN1 has index 0, AIN2 has index 1 etc.) and ´[input_positive]´ (which is the channel input) is the specific analog input, so AIN1 and AIN2.
If channel_id = 0 i.e. index zero into the channel array gets AIN1 then what is the index for channel AIN0?
I have not finished reading your answers but I thought I ask this question in case it affects my understanding of the remainder of your answer.
Kind regards
Mohamed
Another thing I wanted to clarify by using the custom binding of the sample as an example, is this line:
Fullscreen1io-channels = <&adc 0>, <&adc 1>;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXio-channels = <&adc 0>, <&adc 1>;As you can see, the io-channels are ´[&adc 0]´ and ´[&adc 1]´ which maps the ADC peripheral to channel 0 and 1. This just maps the ADC node to the analog input of channel 0 and the analog input of channel 1, which is AIN1 and AIN2, which then maps to GPIO pin P0.04 and P0.05 on the PDK, according to this table describing the mapping of analog pins on the nRF5340 PDK.
According to the PCA10095 schematics of the nRF5340 PDK (nRF5340-QKAA) pin 4 on P0.04 is AIN0 not AIN1.
I have already raised this issue with Martin Lesund about three weeks ago and he said he will get this corrected. There seems to be some discrepancy between the user guide and the schematics. The latter is correct.
So, this means channel_id = 0 i.e. index zero into the channel array points to AIN0.
Kind regards
Mohamed
So, this means channel_id = 0 i.e. index zero into the channel array points to AIN0.
Since it seems we have the channel_id index offset by one in the nRF5340PDK, does it mean the examples referred to will not work as expected?
According to the PCA10095_schematics of the nRF5340PDK pin P0.28 is AIN7. So, I connected a potentiometer to pins: P0.28, VDD, GND and tried to run the light intensity controller example but the adc did not work with this configuration code.
#define ADC_1ST_CHANNEL_ID 7
#define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN7
So, I looked closely to pin P0.28 on the back of the pdk board and realised that P0.28 is actually labelled (A2). So, I changed the config to,
#define ADC_1ST_CHANNEL_ID 2
#define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2
and Bingo! it works. So, it seems that for the nRF5340PDK the values used for ADC_1ST_CHANNEL_ID and ADC_1ST_CHANNEL_INPUT must the same. Any comments?
Kind regards
Mohamed
Hi!
You know what, I misunderstood the description of channel_id. Sorry about that.
At a closer look: "This value primarily identifies the channel within the ADC API". So the value of the channel_id does not matter (in the range of 0 to 7) as long as it is used consistently to identify that channel. This explains why channel ID 0 is used for AIN0 and channel 2 is used for AIN2, here.
My mistake, sorry for the confusion! There is no channel id offset and the sample should work as expected.
Yes, the table I linked to is apparently incorrect, so this is the correct pin mapping.
AIN0 | P0.04 |
AIN1 | P0.05 |
AIN2 | P0.06 |
AIN3 | P0.07 |
AIN4 | P0.25 |
AIN5 | P0.26 |
AIN6 | P0.27 |
AIN7 | P0.28 |
Learner said:Bingo! it works.
Did it work with the analog device plugged into GPIO pin 28 or pin 6?
If it was pin 28, could you attach the file with the path build_folder/zephyr/zephyr.dts just so I can confirm this?
Again, sorry for the confusion.
Best regards,
Heidi