Cannot use AnalogOutput on 4.3

Hello,

I just switched my project to 4.3 from 4.2 and I’m having very hard times with that. The lastest problem, that blocked me completely is Analog output on Cerberus board.
I’m doing this:


			m_app1Out = GTI.AnalogOutputFactory.Create(GT.Socket.GetSocket(3, true, null, null), GT.Socket.Pin.Five, null);
			m_app2Out = GTI.AnalogOutputFactory.Create(GT.Socket.GetSocket(4, true, null, null), GT.Socket.Pin.Five, null);

			m_app1Out.WriteProportion(0);
			m_app2Out.WriteProportion(0);

and upon WriteProportion call I get exception System.ArgumentException with this callstack:
[External Code]
Gadgeteer.dll!Gadgeteer.SocketInterfaces.NativeAnalogOutput.IsActive.set(bool value) Line 40 + 0x3d bytes C#
Gadgeteer.dll!Gadgeteer.SocketInterfaces.NativeAnalogOutput.WriteVoltage(double voltage) Line 52 + 0x4 bytes C#
Gadgeteer.dll!Gadgeteer.SocketInterfaces.AnalogOutput.WriteProportion(double proportion) Line 26 + 0xe bytes C#

GearAssist2_0.exe!GearAssist2_0.Program.InitHW() Line 330 + 0x6a bytes C#

AnalogOutput object seems to be half-initialized:

  •   m_app1Out	
      _channel	0	Microsoft.SPOT.Hardware.Cpu.AnalogOutputChannel {int}
    
  •   _port	null	Microsoft.SPOT.Hardware.AnalogOutput
    
  •   _socket	{3}	Gadgeteer.Socket
      IsActive	0	bool {int}
    

At least, IsActive is clearly false. When I tried m_app1Out.IsActive = true; I’ve got the same exception.
I also tried to access ports throught breadBoardX1 module, with the same result.

Please, anybody, what am I doing wrong?

best regards, Fido

@ fido666 - The current SDK has the analog output channels for the Cerberus wrong. You’ll have to create a raw Microsoft.SPOT.Hardware.AnalogOutput instead of add the FEZCerberus mainboard code to your project and make the fix yourself.

Socket 3 should be Cpu.AnalogOutputChannel.ANALOG_OUTPUT_1
Socket 4 should be Cpu.AnalogOutputChannel.ANALOG_OUTPUT_2

If you plan to make the change yourself, follow https://www.ghielectronics.com/docs/122/gadgeteer-driver-modificationusing https://bitbucket.org/ghi_elect/gadgeteer/src/e8dbae22344b62702996ca499ad69dfd29efb324/Mainboards/GHIElectronics/FEZCerberus/FEZCerberus_43/FEZCerberus_43.cs?at=master as the source, lines 85 and 106.

Thank you very much, you saved my day :wink: This code replaced it:

			
m_app1Out = new AnalogOutput(Cpu.AnalogOutputChannel.ANALOG_OUTPUT_1, 3.3, 0, 12);
m_app2Out = new AnalogOutput(Cpu.AnalogOutputChannel.ANALOG_OUTPUT_2, 3.3, 0, 12);

anyway, as I’m developing something directly for cerb040 mainboard, and I needed also atomic write to both analog outputs, it forced me to search for internal working of analog output on Cerberus and I ended up with low level solution - writing directly to ARM CPU register DAC_DHR12RD.

This works nice, if anybody interested:


		const UInt32 DAC_BASE = 0x40007400;
		Register DAC_CR = new Register(DAC_BASE + 0x00);
		Register DAC_DHR12RD = new Register(DAC_BASE + 0x20);
		DAC_CR.Value = ((uint)((DAC_CR.Value & ~(0x4 | 0x40000)) | (0x1 | 0x10000)));

[...]
		void DACWrite(double a0, double a1)
		{
			uint d0 = (uint)(a0 * 4095.0);
			if (d0 > 4095) d0 = 4095;
			uint d1 = (uint)(a1 * 4095.0);
			if (d1 > 4095) d1 = 4095;
			DAC_DHR12RD.Value = (d0 | (d1 << 16));
		}


well…I’m taking it back. Even this do not work on 4.3 It works on 4.1 and 4.2
On 4.3 only one AnalogOutput works, second one is dead.
Low level access do not work at all (and it worked on older versions).

I give up … going back to 4.2
:wall:

@ fido666 - no wait please. I will try this and let you know.

@ fido666 - What problem are you having?

I did test with clean test app on 4.2 and on 4.3. Here is the code:


using System;
using System.Threading;
using System.IO;
using Microsoft.SPOT;
using GT = Gadgeteer;

using GTM = Gadgeteer.Modules;
using Gadgeteer.Interfaces;

using GHI.OSHW.Hardware;
using GHI.OSHW.Hardware.LowLevel;

[...]
		const UInt32 DAC_BASE = 0x40007400;
		Register DAC_CR = new Register(DAC_BASE + 0x00);
		Register DAC_DHR12RD = new Register(DAC_BASE + 0x20);

		void DACWrite(double a0, double a1)
		{
			uint d0 = (uint)(a0 * 4095.0);
			if (d0 > 4095) d0 = 4095;
			uint d1 = (uint)(a1 * 4095.0);
			if (d1 > 4095) d1 = 4095;
			DAC_DHR12RD.Write(d0 | (d1 << 16));
		}

		// This method is run when the mainboard is powered up or reset.   
		void ProgramStarted()
		{
			AnalogOutput m_app1Out;
			AnalogOutput m_app2Out;
			
			m_app1Out = new AnalogOutput(Gadgeteer.Socket.GetSocket(3, true, null, null), Gadgeteer.Socket.Pin.Five, null);
			m_app1Out.Set(1.5);
			m_app2Out = new AnalogOutput(Gadgeteer.Socket.GetSocket(4, true, null, null), Gadgeteer.Socket.Pin.Five, null);
			m_app2Out.Set(1.5);
			
			DAC_CR.Write((uint)((DAC_CR.Read() & ~(0x4 | 0x40000)) | (0x1 | 0x10000)));


			DACWrite(0.0, 0.0);
			DACWrite(0.5, 0.5);
			DACWrite(1.0, 1.0);


Both methods works fine. Even AnalogOutput and even low level access.I checked voltage on PA04 and PA05 pins of cerb040 and it matched.

Now, something like that in 4.3:


using System;
using System.Threading;
using System.IO;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GT = Gadgeteer;

using GTM = Gadgeteer.Modules;
//using Gadgeteer.SocketInterfaces;
using GHI.Processor;

[...]
		const UInt32 DAC_BASE = 0x40007400;
		Register DAC_CR = new Register(DAC_BASE + 0x00);
		Register DAC_DHR12RD = new Register(DAC_BASE + 0x20);

		void DACWrite(double a0, double a1)
		{
			uint d0 = (uint)(a0 * 4095.0);
			if (d0 > 4095) d0 = 4095;
			uint d1 = (uint)(a1 * 4095.0);
			if (d1 > 4095) d1 = 4095;
			DAC_DHR12RD.Value = (d0 | (d1 << 16));
		}

		// This method is run when the mainboard is powered up or reset.   
		void ProgramStarted()
		{
			AnalogOutput m_app1Out = new AnalogOutput(Cpu.AnalogOutputChannel.ANALOG_OUTPUT_1, 3.3, 0, 12);
			AnalogOutput m_app2Out = new AnalogOutput(Cpu.AnalogOutputChannel.ANALOG_OUTPUT_2, 3.3, 0, 12);
			m_app1Out.Write(1);
			m_app2Out.Write(1);

			
			DAC_CR.Value = ((uint)((DAC_CR.Value & ~(0x4 | 0x40000)) | (0x1 | 0x10000)));


			DACWrite(0.0, 0.0);
			DACWrite(0.5, 0.5);
			DACWrite(1.0, 1.0);




Result is, that low level access works fine too (I must double check my application why it didn’t work there), but AnalogOutput works just for one output (pin PA5). Second one (PA4) don’t react.

@ fido666 - It looks like there is an issue where only one analog output can be active at a time. This has been fixed for the next SDK.

Thank you for clarifying that. As I’m progressing with my tests, I discovered that there is problem with analog inputs too. This code outputs some noise of numbers despite of fact there is 0 volts on their inputs all the time:


			m_app1In = GTI.AnalogInputFactory.Create(GT.Socket.GetSocket(4, true, null, null), GT.Socket.Pin.Four, null);
			m_app2In = GTI.AnalogInputFactory.Create(GT.Socket.GetSocket(4, true, null, null), GT.Socket.Pin.Three, null);

			double v1, v2;
			for (int n = 0; n < 20; n++)
			{
				v1 = m_app1In.ReadProportion();
				v2 = m_app2In.ReadProportion();
				String str = "" v1 " + v1.ToString() + " v2 " + v2.ToString();
				Debug.Print(str);
			}


The same happens in 4.2. Unfortunatelly I cannot go back to 4.1 to test it without reinstalling everything :frowning:

@ fido666 - What type of noise are you seeing?

random numbers between 0 and 1. It’s strange. I tried it on plain Cerb040 board without anything connected to it and also on Cerb040 with analog-output connected over diodes to analog inputs (part of my project) and it does the same. There is not any correlation between what I’m sending on analog output and what I’m getting from analog input.

I’m sure you can reproduce it in debugger just with cerb040/cerberus board. Put there more lines with reading from AnalogInput and each time you press F10, you’ll get different value.

@ fido666 - Using the below code, the analog inputs behave appropriately. Do you have something connected to the pins that is actually pulling them to ground? If you don’t, they will float randomly and give you readings all over between 0 and 1.


using Microsoft.SPOT;
using GT = Gadgeteer;
using GTI = Gadgeteer.SocketInterfaces;

namespace GadgeteerApp1 {
	public partial class Program {
		private GTI.AnalogInput a1;
		private GTI.AnalogInput a2;
		private GT.Timer timer;

		void ProgramStarted() {
			this.a1 = GTI.AnalogInputFactory.Create(GT.Socket.GetSocket(4, true, null, null), GT.Socket.Pin.Four, null);
			this.a2 = GTI.AnalogInputFactory.Create(GT.Socket.GetSocket(4, true, null, null), GT.Socket.Pin.Three, null);

			this.timer = new GT.Timer(100);
			this.timer.Tick += s => Debug.Print(this.a1.ReadProportion().ToString("N2") + " " + this.a2.ReadProportion().ToString("N2"));
			this.timer.Start();
		}
	}
}

1 Like

Mea culpa! You’re right! :wink: I retested it with attached potentiometer and it
works fine.
Sorry for panicking :-[