Playing with the CV1800B ADC

As part of my audio project https://community.milkv.io/t/cv1800b-audio-project/3534 I’ve been working with the ADC on the CV1800B SoC. The kernel driver for the ADC is available in both the V1 and V2 SDKs and there’s a nice example available as well so I was able to get it running and learned a few things:

  • The existing kernel driver is incomplete - it has interfaces for both the usual char device in the /dev directory and a sysfs entry, but the char device read() function will not work as it doesn’t pass its value back to the caller’s buffer. The sysfs show() function on the other hand returns its value as an ASCII string with a decimal numeric value which is easy to read when you just ‘cat’ the file from the command line but requires you to convert it back to an integer so it’s a bit cumbersome to use within a program.
  • The read() and show() functions are similar in that they trigger a conversion and then wait while the ADC is busy before reading the result and returning it. The problem here is that they busywait inside a spinlock_irqsave() so the entire kernel is blocked for 20us while waiting for the conversion. This may be OK if you’re only doing conversions occasionally, but it can seriously hamper performance if conversions are requested frequently.

Because of these issues, I’ve modified the driver to get the read() operation to return a binary value and also digging deeper into how to avoid hogging the system during conversions. There is an IRQ available for the end-of-conversion and there may be a way to use that. I’ve also added some logic to control an external analog MUX via GPIO to get more input channels and this is working well.

The hardware aspect of the ADC seems fine - the datasheet doesn’t go into much detail how it works, but from the register map I’ve been able to infer a lot of the details and it seems sane. Overall performance of the converter isn’t great - I see a fair amount of sample-to-sample noise with a standard deviation of about 5 lsbs near max input range but I suppose that’s to be expected on a complex SoC like this. With a bit of post-processing in software it will be usable.

Modified driver here: https://github.com/emeb/duo-buildroot-sdk-v2/blob/audio_board/osdrv/interdrv/saradc/cv180x/cvi_saradc.c

Analysis code here: duo-examples/dev_adc at main · emeb/duo-examples · GitHub

3 Likes

upstream has a driver in /drivers/iio/adc

As a side note

  • what is your target board as from build.sh
  • what is your driver for your LCD (is this in upstream)
1 Like

Yes - it’s at drivers/iio/adc/sophgo-cv1800b-adc.c and it looks much more complete than the one in the SDK kernel tree. Thanks for the heads-up!

Side note answers:

  • Using just the standard cv1800b_milkv_duo_musl_riscv64_sd board spec.
  • LCD driver is a slightly modified fbtft-core from the 5.10 kernel in the SDK, targeting the ST7789 display in my system.
1 Like

I don’t (currently) know if the driver is accessible for sound …

ST7789 is also upstream.

currently I can compile v6.16 with the “buildroot-sdk”, with newer config, whats missing is a proper dts for sg200x devices. The whole pincontrol thing is only generic ..

1 Like

Audio drivers for CV18xx on-chip codec and I2S are found in the kernel sound/soc/cvitek directory of the SDK’s 5.10 fork which does not exist upstream and there doesn’t appear to be a Sophgo directory either so they haven’t been renamed AFAICT.

To my knowledge the ST7789 fbdev driver I’m using is unmodified and should work with upstream, however as mentioned I did make a minor change to the fbtft driver to correct the reset behavior.

1 Like

audio drivers are not upstream, because they need to ne factored, massively

The are some global symbols, so you can use only one driver at a time. I’ve compiled them with 6.17-rc. But they have some similarities for different SoC, maybe also in hardware.

And these are the easy drivers

The worst drivers are the bundle Camera (CSI) , Display (DSI) , VideoProcessorSubSystem (VPSS)

Take your favorate word, from the list of bad/ugly words

2 Likes

IIRC

upstream has a feature in DTS devicetree. active low or active high reset, maybe this is done via GPIO definition. But first a proper pinmux is needed.

2 Likes