Skip to content

driver:adc: adc16 dma support async and repeat sample #56120

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

Merged
merged 1 commit into from
Apr 13, 2023
Merged

driver:adc: adc16 dma support async and repeat sample #56120

merged 1 commit into from
Apr 13, 2023

Conversation

hakehuang
Copy link
Collaborator

@hakehuang hakehuang commented Mar 22, 2023

add support for async call and repeat sample test

  1. change the DMA req to 2 byte each
  2. increase the buffer pre-dma
  3. add protection on invalid buffer

depends on: PR #56104
fixing: issue #56070

@hakehuang
Copy link
Collaborator Author

@heinwessels , this is my test result log

*** Booting Zephyr OS build zephyr-v3.3.0-1517-gdba786cddd60 ***
Running TESTSUITE adc_dma
===================================================================
START - test_adc_asynchronous_call
Samples read: 0x0377 0x0379 0x0379 0x0377 0x0379 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
 PASS - test_adc_asynchronous_call in 0.024 seconds
===================================================================
START - test_adc_invalid_request
E: Invalid resolution
E: Invalid resolution
Samples read: 0x0379 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
 PASS - test_adc_invalid_request in 0.029 seconds
===================================================================
START - test_adc_repeated_samplings
repeated_samplings_callback: done 1
Samples read: 0x037a 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 2
Samples read: 0x037a 0x02ff 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 3
Samples read: 0x037a 0x0377 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 4
Samples read: 0x037a 0x0375 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 5
Samples read: 0x037a 0x0379 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 6
Samples read: 0x037a 0x0373 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 7
Samples read: 0x037a 0x0376 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 8
Samples read: 0x037a 0x0373 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 9
Samples read: 0x037a 0x0379 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
repeated_samplings_callback: done 10
Samples read: 0x037a 0x0379 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
 PASS - test_adc_repeated_samplings in 0.101 seconds
===================================================================
START - test_adc_sample_one_channel
Samples read: 0x0377 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
 PASS - test_adc_sample_one_channel in 0.025 seconds
===================================================================
START - test_adc_sample_two_channels
 SKIP - test_adc_sample_two_channels in 0.001 seconds
===================================================================
START - test_adc_sample_with_interval
now spend = 0ms
now spend = 0ms
Samples read: 0x0379 0x0376 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000 0xffff8000
0xffff8000 0xffff8000 0xffff8000
 PASS - test_adc_sample_with_interval in 0.028 seconds
===================================================================
TESTSUITE adc_dma succeeded

------ TESTSUITE SUMMARY START ------

SUITE PASS - 100.00% [adc_dma]: pass = 5, fail = 0, skip = 1, total = 6 duration = 0.208 seconds
 - PASS - [adc_dma.test_adc_asynchronous_call] duration = 0.024 seconds
 - PASS - [adc_dma.test_adc_invalid_request] duration = 0.029 seconds
 - PASS - [adc_dma.test_adc_repeated_samplings] duration = 0.101 seconds
 - PASS - [adc_dma.test_adc_sample_one_channel] duration = 0.025 seconds
 - SKIP - [adc_dma.test_adc_sample_two_channels] duration = 0.001 seconds
 - PASS - [adc_dma.test_adc_sample_with_interval] duration = 0.028 seconds

------ TESTSUITE SUMMARY END ------

===================================================================
PROJECT EXECUTION SUCCESSFUL

@@ -62,6 +62,7 @@ struct mcux_adc16_data {
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
const struct device *dev_dma;
struct adc_edma_config adc_dma_config;
bool batch_mode; /* batch conversion mode */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is batch_mode set? And what's the difference between this and continuous_convert?

Copy link
Collaborator Author

@hakehuang hakehuang Mar 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@heinwessels , this is leaved for your RFC get merge, and I will change accordingly. the continuous_convert in NXP hardware means it will continues convert sample so the adc data register will keep updated, until adc abort this. which is a pure hardware behavour. this is why I want to seperate this from your RFC's continues, see #55783 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I understand. It's not 100% certain if it will get added to the API though, and even if will still be called batch_mode. But I guess you can always change it in that case.

data->adc_dma_config.dma_block.block_size = ctx->sequence.buffer_size;
data->adc_dma_config.dma_block.block_size = 2;
if (data->batch_mode) {
data->adc_dma_config.dma_block.block_size = ctx->sequence.buffer_size;
Copy link
Contributor

@heinwessels heinwessels Mar 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how batch_mode works, but should it maybe depend on extra_samples, for example:

Suggested change
data->adc_dma_config.dma_block.block_size = ctx->sequence.buffer_size;
data->adc_dma_config.dma_block.block_size *= 1 + data->ctx.options.extra_samplings;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@heinwessels , I check your RFC #55783 , which says in continues mode it will convert till buffer is full, so I set it to the whole buffer size

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, okay, but it seems I wasn't clear in the RFC, because that's not what I meant :)

  • It will always set the DMA amount to transfer to number_of_channels * (1 + extra_samplings), regardless of how big the given buffer is. (It does make sure it's big enough).
  • In the case of the STM32 the end of the read will be when the DMA Buffer Full Interrupt is raised. This has nothing to do with the actual buffer size.

And simply setting it to buffer_size will not allways work. What if the user specifies 2 channels with extra_samples = 1. That will result in 2 * (1 + 1) * sizeof(int16_t) = 8.

  • What if the user supplied a buffer_size is smaller than 8?
    • STM32 driver throws an error in this case.
  • What if the user supplied a buffer_size is bigger than 8? What if it's bigger by 2 (meaning 10)? That's not enough enough for a entire sample of 2 channels, what should the driver do then?
    • STM32 driver ignores the extra given space, using the calculation I suggested. It's of course also possible to throw an error, but this will change what all the unit tests expect. The unit tests always give the same buffer and same buffer_size, regardless of the actual samplings expected. Therefore, I would expect the ADC driver to always ignore the extra bytes.

IMO the suggestion is the safer approach.

Copy link
Collaborator Author

@hakehuang hakehuang Mar 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@heinwessels , in continues mode, my understanding is that we shall ignore the extra_sampling at all, and use as many buffer as possible, if user set buffer to small, then we can throw an exception. in none continues mode the extra_sampling will take effects, remember in the task_repeated_samplings case, if we do DMA for all required samples + extras, and the code in the adc_context will be confused, and we need skip them, why not just set skip the extra settings and use the buffer size directly, because by all means use need set the buffer size correctly. Because in the continues mode, the customer is expection to handle enough samples they want in maximum.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because by all means use need set the buffer size correctly

This is not the case. Almost all drivers only has a check (something like check_buffer_size) to ensure the buffer is big enough. Have a search for buffer_size < in the drivers/adc/ folder, and you will see. For example:

if (sequence->buffer_size < needed_buffer_size) {
LOG_ERR("Provided buffer is too small (%u/%u)",
sequence->buffer_size, needed_buffer_size);
return -ENOMEM;
}

None of the other drivers force the buffer to be of the correct size. Additionally, if this is forced, then most of the current unit tests will also fail. In most of the current tests the supplied buffer is bigger than what's required, because the driver handles this correctly.

IMO it's very important that all drivers in Zephyr work the same when looking from the outside. :)

Copy link
Collaborator Author

@hakehuang hakehuang Mar 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, if this is forced, then most of the current unit tests will also fail. In most of the current tests the supplied buffer is bigger than what's required, because the driver handles this correctly.

by default, current unit test does not set the continues(batch_mode in NXP driver), they will pass, and we just need add a case to enable it once the RFC final. and for continues mode, user shall provide a correct buffer size(this can be document), the point here is for continues mode, the setting is to only set the continues flag(and leave the extra_samples to 0), and the correct buffer size. the driver will try to fill the buffer size as quick as possible, and do minimal check. if we enforce that the block_size = 2*(1+extra), and the continues flag, the adc_context need modify to handle it separately. and the extra_samples can not be used to repeated_samplings case. Would this be more confused? anyway, I think we can continue discuss with your RFC, as this is not this PR mainly for, agree?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and for continues mode, user shall provide a correct buffer size(this can be document)

We could do this of course, but I don't think it should be different than other ways of sampling, which doesn't care that the buffer itsn't to big. So it would not be consistent.

by default, current unit test does not set the continues(batch_mode in NXP driver)

Also true of course, but when we add a test then it will fail, because other drivers will not implement it this way, because it would not be consistent with the way the rest of the driver works.

Regardless, this is debating over a feature that's not supported yet in Zephyr. It could still take any shape. This also means it's dead code at the moment. Therefore, adding support for it already doesn't really make sense IMO.

And also, I don't have a stake in NXP, because I've not used an NXP MCU, or worked on it's drivers. I just throught it might want to implement functionality in a consistent way with other drivers.

Copy link
Collaborator Author

@hakehuang hakehuang Mar 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do this of course, but I don't think it should be different than other ways of sampling, which doesn't care that the buffer itsn't to big. So it would not be consistent.

in your proposal, the repeated_samplings would not work, and we need skip it for continues mode. and if user do not provide big enough buffer, it will not fail from driver side, it is just application issue, and our test can be set correctly.

This also means it's dead code at the moment

it is not dead code, you can trigger it by set batch_mode = true in adc_init function. which just not open to user, but the fucntion is OK. and I do respect your concerns, let's wait the review from others, and update accordingly. Thanks a lot.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hakehuang I'm inclined to agree with @heinwessels here- While the user could enable batch mode by modifying the driver, that is not something exposed to the user or (more importantly, IMO) any test infrastructure in Zephyr. I appreciate you implementing this support, but I think if we want to support this feature we should do it as a separate PR (based on the commits in the RFC for the time being). What are your thoughts here?

Copy link
Collaborator Author

@hakehuang hakehuang Apr 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danieldegrasse , I see. let me remove the batch_mode code. done

heinwessels
heinwessels previously approved these changes Mar 23, 2023
Copy link
Contributor

@heinwessels heinwessels left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does fix the NXP adc_dma unit tests.

As mentioned in the comments, there are still things that are not consistent with other drivers, but this might be good enough for the moment. I'll leave this for other reviewers that work with NXP.

@hakehuang
Copy link
Collaborator Author

hakehuang commented Mar 28, 2023

@anangl can you help to review this fixes?

@MaureenHelm
Copy link
Member

@danieldegrasse can you take a look please?

teburd
teburd previously approved these changes Apr 11, 2023
add support for async call and repeat sample test

1. change the DMA req to 2 byte each
2. increase the buffer pre-dma
3. add protection on invalid buffer

depends on: PR #56104
fixing: issue #56070

Signed-off-by: Hake Huang <[email protected]>
@hakehuang hakehuang dismissed stale reviews from teburd and heinwessels via 72d49fe April 12, 2023 15:14
@hakehuang hakehuang requested review from teburd and heinwessels April 12, 2023 15:15
@carlescufi carlescufi merged commit e01586a into zephyrproject-rtos:main Apr 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: ADC Analog-to-Digital Converter (ADC) platform: NXP NXP
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants