Porting SC20260N: TinyCLR 2.3.0 → 3.0.1

Porting SC20260N: TinyCLR 2.3.0 → 3.0.1

Migrating a fielded handheld from 2.3.0 to 3.0.1.6001 on SITCore SC20260N, one shared source tree
building both. Below is only what did not go smoothly, grouped by where it stands. Happy to post
a minimal runnable repro for any of these - say which and we will put it up.


[Summary by Claude, who did most of the work! :grinning_face_with_smiling_eyes: ]

Still open

1. Internal temperature sensor (ADC3 channel 18) reads ~15 C high

Same board, same room, flipping between a 2.3 and a 3.0 build within minutes - far too fast for a
real change in die temperature.

Identical arithmetic both sides, same calibration registers (ts1 = 12429, ts2 = 16441, read
from 0x1FF1E820 / 0x1FF1E840), and ResolutionInBits reports 16 on both.

build raw reported
2.3, one conversion ~12730 ~35 C (21 C room, 30 C module surface by IR)
3.0, one conversion ~5400 -110 C
3.0, plateau after 5+ conversions ~13450 ~50 C

On 3.0 the channel needs about five back-to-back conversions to stabilise, and any pause resets
it
. Eight successive ReadValue() calls, then one more taken immediately after printing them:

P1: 9654 11798 13048 13480 13370 13461 13428 13452
T = -110.75 C (raw=5370)   <-- read taken right after printing the line above

A single Debug.WriteLine was enough to drop it from 13452 back to 5370. On 2.3 none of this
happens: one conversion on a freshly opened channel is correct immediately.

To us that looks like insufficient acquisition time on a channel the STM32H7 reference manual says
needs a long sampling time.

  • Did ADC sampling time, clock prescaler, or oversampling change for the internal channels in 3.0?
  • Is there any supported way to set sampling time from managed code?

Note the plateau is still ~5.7% high in raw counts, so “settle it for longer” does not look like
the whole answer.

2. Power.Sleep / RTC wake

We sleep in repeated 30 second slices with a watchdog rather than one long Power.Sleep, because
long sleeps did not reliably wake (2.2-era issue). Does 3.0.1 change this on SC20260N? We would
like to drop the chunking - it costs real battery life on a handheld.


Worked around, cause not understood

3. Dispatch appears to run the wrong overload’s body (byte vs string)

Every WiFi request threw CLR_E_WRONG_TYPE at the first access of a byte[] parameter:

void WriteWithTimeout(byte[] Data, int timeout)
{
    var n = Data.Length;        // throws here

Data.GetType().FullName, logged immediately before that line, returns System.String. It is
declared byte[] and every caller in the chain passes a byte[].

The class declares two methods named WriteWithTimeout differing only by a byte[] versus
string first parameter (and a second pair follows the same pattern). Renaming so that no two
methods share a name fixed it completely. We applied the rename to 2.3 as well, in case it is
latent there.

  • Is this known in 3.0?
  • Is the risky pattern narrower than “same-named methods” - base/derived, or across an interface?

We have not isolated a minimal repro yet, but will build one if this is not already familiar.

4. API changes we adapted to

  • Net.WebUtility no longer publicly exported.
  • Cryptography.SHA1 now internal; public SHA1 moved to a separate assembly.
  • WatchdogController.Enable takes TimeSpan, not uint ms. An improvement, just a compile break.
  • Templates default LangVersion to 12 where 2.3 defaulted to 9 - a surprise in a shared-source
    build.

Ours, not yours - pointers for anyone else porting

Both were real bugs in our own 2.3 code that 2.3 tolerated silently for years.

5. DacController.OpenChannel now validates the index

We passed SC20260.GpioPin.PA5 (= 5) where SC20260.Dac.PA5 (= 1) was wanted; the part has two
DAC channels. 2.3 accepted it silently, 3.0 throws - correctly. The trap is that both constants are
named PA5 in different nested classes, so the wrong one reads perfectly plausibly at the call
site.

6. Two threads on one ADC controller, unsynchronised

A battery monitor reading VRef2p5 continuously on its own thread, plus on-demand temperature
reads elsewhere, each with their own AdcController and AdcChannel against the same physical
ADC3, with nothing serialising them. On 3.0 this gave wildly inconsistent readings including large
negatives. One shared lock fixed it, and we applied it to 2.3 too - the hazard is real there, the
window just never seems to have been hit.

Worth auditing before you port if two subsystems in your codebase happen to touch one controller
independently.

1 Like

Nice, thks for sharing, we will look into 1,2,3 and 6.
4, 5 are NAB.

1 Like

Aren’t that sweet, having a well knowledged assistant on your side? We love it.

1 Like