2014年4月1日 星期二

Control two MCP2515 chips

I modified the source code of MCP2515.ccp
(http://code.google.com/p/netduino-mcp2515/downloads/list)
to meet my project's requirement.
 It support two CAN bus protocol chips and control by one SPI interface.

//-------------------------------------------------------------------------------------------
 using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace System
{
    /// <summary>
    /// Represents a class that handles the CAN transceiver MCP2515.
    /// </summary>
    public class MCP2515
    {
        //-------------------------------------
        #region REGISTERS
        //-------------------------------------
        private const byte RXF0SIDH = 0x00;
        private const byte RXF0SIDL = 0x01;
        private const byte RXF0EID8 = 0x02;
        private const byte RXF0EID0 = 0x03;
        private const byte RXF1SIDH = 0x04;
        private const byte RXF1SIDL = 0x05;
        private const byte RXF1EID8 = 0x06;
        private const byte RXF1EID0 = 0x07;
        private const byte RXF2SIDH = 0x08;
        private const byte RXF2SIDL = 0x09;
        private const byte RXF2EID8 = 0x0A;
        private const byte RXF2EID0 = 0x0B;
        private const byte BFPCTRL = 0x0C;
        private const byte TXRTSCTRL = 0x0D;
        private const byte CANSTAT = 0x0E;
        private const byte CANCTRL = 0x0F;
        private const byte RXF3SIDH = 0x10;
        private const byte RXF3SIDL = 0x11;
        private const byte RXF3EID8 = 0x12;
        private const byte RXF3EID0 = 0x13;
        private const byte RXF4SIDH = 0x14;
        private const byte RXF4SIDL = 0x15;
        private const byte RXF4EID8 = 0x16;
        private const byte RXF4EID0 = 0x17;
        private const byte RXF5SIDH = 0x18;
        private const byte RXF5SIDL = 0x19;
        private const byte RXF5EID8 = 0x1A;
        private const byte RXF5EID0 = 0x1B;
        private const byte TEC = 0x1C;
        private const byte REC = 0x1D;
        private const byte RXM0SIDH = 0x20;
        private const byte RXM0SIDL = 0x21;
        private const byte RXM0EID8 = 0x22;
        private const byte RXM0EID0 = 0x23;
        private const byte RXM1SIDH = 0x24;
        private const byte RXM1SIDL = 0x25;
        private const byte RXM1EID8 = 0x26;
        private const byte RXM1EID0 = 0x27;
        private const byte CNF3 = 0x28;
        private const byte CNF2 = 0x29;
        private const byte CNF1 = 0x2A;
        private const byte CANINTE = 0x2B;
        private const byte MERRE = 7;
        private const byte WAKIE = 6;
        private const byte ERRIE = 5;
        private const byte TX2IE = 4;
        private const byte TX1IE = 3;
        private const byte TX0IE = 2;
        private const byte RX1IE = 1;
        private const byte RX0IE = 0;
        private const byte CANINTF = 0x2C;
        private const byte MERRF = 7;
        private const byte WAKIF = 6;
        private const byte ERRIF = 5;
        private const byte TX2IF = 4;
        private const byte TX1IF = 3;
        private const byte TX0IF = 2;
        private const byte TX0IF_MASK = 0x04;
        private const byte RX1IF = 1;
        private const byte RX0IF = 0;
        private const byte RX1IF_MASK = 0x02;
        private const byte RX0IF_MASK = 0x01;
        private const byte EFLG = 0x2D;
        private const byte TXB0CTRL = 0x30;
        private const byte TXREQ = 3;
        private const byte TXB0SIDH = 0x31;
        private const byte TXB0SIDL = 0x32;
        private const byte EXIDE = 3;
        private const byte EXIDE_MASK = 0x08;
        private const byte TXB0EID8 = 0x33;
        private const byte TXB0EID0 = 0x34;
        private const byte TXB0DLC = 0x35;
        private const byte TXRTR = 7;
        private const byte TXB0D0 = 0x36;
        private const byte RXB0CTRL = 0x60;
        private const byte RXM1 = 6;
        private const byte RXM0 = 5;
        private const byte RXRTR = 3;
        // Bits 2:0 FILHIT2:0
        private const byte RXB0SIDH = 0x61;
        private const byte RXB0SIDL = 0x62;
        private const byte RXB0EID8 = 0x63;
        private const byte RXB0EID0 = 0x64;
        private const byte RXB0DLC = 0x65;
        private const byte RXB0D0 = 0x66;
        //-------------------------------------
        #endregion REGISTERS
        //-------------------------------------
       
        //MCP2515 Command Bytes
        private readonly byte RESET = 0xC0;
        private readonly byte READ = 0x03;
       // private readonly byte READ_RX_BUFFER = 0x90;
        private readonly byte WRITE = 0x02;
       // private readonly byte LOAD_TX_BUFFER = 0x40;
       // private readonly byte RTS = 0x80;
       // private readonly byte READ_STATUS = 0xA0;
       // private readonly byte RX_STATUS = 0xB0;
        private readonly byte BIT_MODIFY = 0x05;
        /// <summary>Represent a LOW  (false) state.</summary>
        private const bool LOW = false;
        /// <summary>Represent a HIGH (true) state.</summary>
        private const bool HIGH = true;
        /// <summary></summary>
        private const byte DataIndexOffset = 2;
        /// <summary>The max CAN ID that can be represented on an 11 bit ID.</summary>
        private const int CANID_11BITS = 0x7FF;
        //-------------------------------------------------------------
        //// This must be modified for your CAN ID
        private const uint VMS_CAN0_ID = 0x7E8, VMS_CAN1_ID = 0x329;
        //-------------------------------------------------------------
        // This must be modified depend on hardware
        /// <summary>SPI PIN for VMS control.</summary>
        public const  Cpu.Pin SPI_CAN1_SEL = (Cpu.Pin)45;    // PC13
        public const  Cpu.Pin SPI_CAN0_SEL = (Cpu.Pin)1;     // PA1
        /// <summary>the SPI object that communicate with the transceiver.</summary>
        private SPI spi;
         // Configure SPI  CAN channel0 and channel1           
        private  SPI.Configuration [] configSPI = new SPI.Configuration[2];
       
    
        /// <summary>
        /// Represents the available baud rates.
        /// </summary>
        public enum enBaudRate
        {
            CAN_BAUD_10K = 1,  CAN_BAUD_50K = 2, CAN_BAUD_100K = 3,
            CAN_BAUD_125K = 4, CAN_BAUD_250K = 5, CAN_BAUD_500K = 6
        }
        /// <summary>Represents a CAN message.</summary>
        public class CANMSG
        {
            public uint CANID { get; set; }
            public bool IsExtended { get { return CANID > CANID_11BITS; } }
            public bool IsRemote { get; set; }
            public int DataLength { get { return data.Length; } }
            public byte[] data = new byte[8];
        } 
        /// <summary>Initialize the CAN transceiver.</summary>
        /// <param name="baudrate">The selected baud rate.</param>
        /// <returns>True if configuration was successful.</returns>
        /// <remarks>Transceiver needs to be set to normal mode before starting TX/RX operations.</remarks>
        public bool InitCAN(enBaudRate baudrate)
        {
           configSPI[0] = new SPI.Configuration(SPI_CAN0_SEL, LOW, 0, 0, HIGH, HIGH, 10000, SPI.SPI_module.SPI1);
           configSPI[1] = new SPI.Configuration(SPI_CAN1_SEL, LOW, 0, 0, HIGH, HIGH, 10000, SPI.SPI_module.SPI1); 
       
            spi = new SPI(configSPI[0]);
            // Write reset to the CAN0/CAN1 transceiver.
            spi.Write(new byte[] {RESET});
            spi.Config = configSPI[1];
            spi.Write(new byte[] {RESET});
            //Read mode and make sure it is config
            Thread.Sleep(100);
          
            byte mode0 = (byte)(ReadRegister(0,CANSTAT) >> 5);
            byte mode1 = (byte)(ReadRegister(1,CANSTAT) >> 5);
            if ((mode0 != 0x04) || (mode1 != 0x04))
            {
                return false;
            }
            else // ------ Config mode -------------------
            {
                VMS_FilterInit();
                SetCANBaud(baudrate); // will set to normal
                SetCANNormalMode();
                VMS_CAN0IdFilter();
                //--------------- normal mode -----------------
               
                return true;
            }
        }
     
        /// <summary>Set the CAN baud rate.</summary>
        /// <param name="baudrate">The configured baud rate.</param>
        /// <returns>True if configured.</returns>
        private bool SetCANBaud(enBaudRate baudrate)
        {
            byte brp;
 
            //BRP<5:0> = 00h, so divisor (0+1)*2 for 125ns per quantum at 16MHz for 500K  
            //SJW<1:0> = 00h, Sync jump width = 1
            switch (baudrate)
            {
                case enBaudRate.CAN_BAUD_10K:
                    brp = 5;
                    break;
                case enBaudRate.CAN_BAUD_50K:
                    brp = 4;
                    break;
                case enBaudRate.CAN_BAUD_100K:
                    brp = 3;
                    break;
                case enBaudRate.CAN_BAUD_125K:
                    brp = 2;
                    break;
                case enBaudRate.CAN_BAUD_250K:
                    brp = 1;
                    break;
                case enBaudRate.CAN_BAUD_500K:
                    brp = 0;
                    break;
                default:
                    return false;
                  
            }
          
            byte[] cmdBuffer = new byte[] { WRITE, CNF1, (byte)(brp & 0x3F) };
            spi.Config = configSPI[0];
            spi.Write(cmdBuffer);
            //-------------------------------------------------
            //PRSEG<2:0> = 0x01, 2 time quantum for prop
            //PHSEG<2:0> = 0x06, 7 time constants to PS1 sample
            //SAM = 0, just 1 sampling
            //BTLMODE = 1, PS2 determined by CNF3
          
            spi.Write(new byte[] { WRITE, CNF2, 0xB1 });
            //-----------------------------------------------
            //PHSEG2<2:0> = 5 for 6 time constants after sample
            //SOF enable <bit7>
            spi.Write(new byte[] { WRITE, CNF3, 0x85 });
            spi.Config = configSPI[1];
            spi.Write(cmdBuffer);
            spi.Write(new byte[] { WRITE, CNF2, 0xB1 });
            spi.Write(new byte[] { WRITE, CNF3, 0x85 });
            //SyncSeg + PropSeg + PS1 + PS2 = 1 + 2 + 7 + 6 = 16
            return true;
        }
        /// <summary>Writes a value to the selected register.</summary>
        /// <param name="registerAddress">The address of the register.</param>
        /// <param name="value">The value to be write to the register.</param>
        private void WriteRegister(uint channel ,byte registerAddress, byte value)
        {
            spi.Config = configSPI[channel];
            spi.Write(new byte[] { WRITE, registerAddress, value});
          
          
        }
        /// <summary>Reads the value of the selected register.</summary>
        /// <param name="registerAddress">The address of the register.</param>
        /// <returns>A byte with the value read from the register.</returns>
        private byte ReadRegister(uint channel,byte registerAddress)
        {
            byte[] CmdBuffer = new byte[] { READ, registerAddress };
            byte[] outData = new byte[1];
            spi.Config = configSPI[channel];
            spi.WriteRead(CmdBuffer, outData, 2);
         
            return outData[0];
        }
        /// <summary>Writes a bit to a register.</summary>
        /// <param name="registerAddress">The address of the register that supports bit writing.</param>
        /// <param name="bitNumber">The zero index based of the bit to write.</param>
        /// <param name="value">the value of the bit to write.</param>
        private void WriteRegisterBit(uint channel,byte registerAddress, byte bitNumber, byte value)
        {
            spi.Config = configSPI[channel];
            //spi.Write(new byte[] { BIT_MODIFY, regno, (byte)(1 << bitno) });
            if (value != 0)
            {
            
                spi.Write(new byte[] { BIT_MODIFY, registerAddress, (byte)(1 << bitNumber), 0xFF });
             
            }
            else
            {
              
                    spi.Write(new byte[] { BIT_MODIFY, registerAddress, (byte)(1 << bitNumber), 0x00 });
            }
        }
        /// <summary>Transmit a CAN message to the bus.</summary>
        /// <param name="message">The CAN Message to be transmitted.</param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool Transmit(uint channel ,CANMSG message, int timeout)
        {
            // Holds if message was sent or not.
            bool sentMessage = false;
            // Calculate the end time based on current device time.
           TimeSpan startTime = Utility.GetMachineTime();
           TimeSpan endTime = startTime.Add(new TimeSpan(0,0,0,0,timeout));
            //--------------------------------------
            // Set the CAN ID.
            byte val = 0x00;
            uint bit11Address = 0x00;
            uint bit18Address = 0x00;
           
            // Build Extended CAN ID
            if (message.IsExtended)
            {
                // Split the 11 bit and 18 bit sections of the ID.
                bit11Address = (uint)((message.CANID >> 16) & 0xFFFF);
                bit18Address = (uint)(message.CANID & 0xFFFFF);
                // Set the first part of the ID
                val = (byte)(bit11Address >> 5);
                WriteRegister(channel,TXB0SIDH, val);
                // Set the second part of the ID.
                val = (byte)(bit11Address << 3);
                val |= (byte)(bit11Address & 0x07);
                // Mark the message as extended.
                val |= 1 << EXIDE;
                WriteRegister(channel, TXB0SIDL, val);
                // Write the 18 bit part of the ID
                val = (byte)(bit18Address >> 8);
                WriteRegister(channel, TXB0EID8, val);
                val = (byte)(bit18Address);
                WriteRegister(channel, TXB0EID0, val);
            }
            else
            {
                // Transmit a 11 bit ID.
                bit11Address = (uint)(message.CANID);
                val = (byte)(bit11Address >> 3);
                WriteRegister(channel, TXB0SIDH, val);
                val = (byte)(bit11Address << 5);
                WriteRegister(channel, TXB0SIDL, val);
            }

            //--------------------------------------
            val = (byte)(message.DataLength & 0x0f);
            // Check if is a remote frame
            if (message.IsRemote)
            {
                // Mark the frame as remote
                val |= (byte)(1UL << (TXRTR));
                WriteRegisterBit(channel, val, TXRTR, 1);
            }
            WriteRegister(channel, TXB0DLC, val);
            //--------------------------------------
            //Write Message Data
            byte[] txDATA = new byte[10];
            txDATA[0] = WRITE;
            txDATA[1] = TXB0D0;
            for (int i = DataIndexOffset; i < message.DataLength + DataIndexOffset; i++)
            {
                txDATA[i] = message.data[i - DataIndexOffset];
            }
            spi.Config = configSPI[channel];
            spi.Write(txDATA);
            //----------------------
            // Command to transmit the CAN message
            WriteRegisterBit(channel,TXB0CTRL, TXREQ, 1);
           
            //----------------------
            // Wait until time out to get confirmation of message was sent.
           while (Utility.GetMachineTime() < endTime)
           {
                val = ReadRegister(channel, CANINTF);           
                if((val & TX0IF_MASK ) == TX0IF_MASK )
                {
                    sentMessage = true;
                 break;
                }
            }
            ////Abort the send if failed
            WriteRegisterBit(channel, TXB0CTRL, TXREQ, 0);
 
            ////And clear write interrupt
            WriteRegisterBit(channel, CANINTF, TX0IF, 0);
            return sentMessage;
        }
        /// <summary>
        /// Check if a new message was received by the transceiver.
        /// </summary>
        /// <param name="msg">The CAN message that will contain the retrived message.</param>
        /// <param name="timeout">The time to wait if a message become available.</param>
        /// <returns>True if a message was received.</returns>
        public bool Receive(uint channel,out CANMSG msg, int timeout)
        {
            bool gotMessage = false;
            uint val;
            msg = new CANMSG();
           TimeSpan startTime = Utility.GetMachineTime();
           TimeSpan endTime = startTime.Add(new TimeSpan(0, 0, 0, 0, timeout));
            gotMessage = false;
            while (Utility.GetMachineTime() < endTime)
            {
                val = ReadRegister(channel, CANINTF);
                //If we have a message available, read it
                if ((val & RX0IF_MASK) == RX0IF_MASK)
                {
                    gotMessage = true;
                   break;
                }
            }
            if (gotMessage)
            {
                val = ReadRegister(channel, RXB0CTRL);
                msg.IsRemote = ((val & 0x04) == 0x04) ? true : false;
                //Address received from
                uint adddresVal = 0;
                val = ReadRegister(channel, RXB0SIDH);
                adddresVal |= (val << 3);
                val = ReadRegister(channel, RXB0SIDL);
                adddresVal |= (val >> 5);
                bool isExtended = ((val & EXIDE_MASK) == EXIDE_MASK) ? true : false;
                uint adddresExtVal = 0;
                if (isExtended)
                {
                    adddresExtVal = (uint)((val & 0x03) << 16);
                    val = ReadRegister(channel, RXB0EID8);
                    adddresExtVal |= (uint)(val << 8);
                    val = ReadRegister(channel, RXB0EID0);
                    adddresExtVal |= val;
                    adddresVal = ((adddresVal << 18) | adddresExtVal);
                }
                msg.CANID = (uint)adddresVal;
                //Read data bytes
                val = ReadRegister(channel,RXB0DLC);
                uint dataLen = (val & 0xf);
                byte[] CmdBuffer = new byte[] { READ, RXB0D0 };
                msg.data = new byte[dataLen];
                spi.Config = configSPI[channel];
                spi.WriteRead(CmdBuffer, msg.data, 2);
             
                //And clear read interrupt
                WriteRegisterBit(channel,CANINTF, RX0IF, 0);
            }
            else
            {
            }
            return gotMessage;
        }

        /// <summary>Set transceiver to normal state.</summary>
        /// <remarks>This state needs to be selected before starting TX/RX.</remarks>
        public void SetCANNormalMode()
        {
            //REQOP2<2:0> = 000 for normal mode
            //ABAT = 0, do not abort pending transmission
            //OSM = 0, not one shot
            //CLKEN = 1, disable output clock
            //CLKPRE = 0b11, clk/8
             WriteRegister(0,CANCTRL,0x07);
             WriteRegister(1,CANCTRL,0x07);
           
            //Read mode and make sure it is normal
            byte mode = ReadRegister(0,CANSTAT);
            ReadRegister(1, CANSTAT);
            mode = (byte)(mode >> 5);
            if (mode != 0)
            { }
            // Set RX buffer control to turn filters OFF and receive any message.      
            WriteRegister(0,RXB0CTRL, 0x60);
            WriteRegister(1,RXB0CTRL, 0x60);
        }
        //--------------------------------------------------------------
        //                      VMS_FilterInit()
        //purpose : write the filter to CAN0'Receiver buf0 and buf1
        //          to receive the VMS_CAN0_ID and VMS_CAN1_ID
        //-------------------------------------------------------------
        private void VMS_FilterInit()
        {
            WriteRegister(0, RXF0SIDH, (byte)(VMS_CAN0_ID >> 3));
            WriteRegister(0, RXF0SIDL , (byte)((VMS_CAN0_ID << 5)&0xe0));
            WriteRegister(0, RXF1SIDH, (byte)(VMS_CAN1_ID >> 3));
            WriteRegister(0, RXF1SIDL, (byte)((VMS_CAN1_ID << 5) & 0xe0));
            WriteRegister(0, RXM0SIDH, 0xff); // config the MASK
            WriteRegister(0, RXM0SIDL, 0xff);
        }
      
        //---------------------------------------------
        public void VMS_CAN0IdFilter()
        {
            WriteRegister(0, RXB0CTRL, 0x0); // receive the standard/ext ID with RXF0 filter 
        }
        //---------------------------------------------
        public void VMS_CAN1IdFilter()
        {
            WriteRegister(0, RXB0CTRL, 0x1); // receive the standard/ext ID with RXF1 filter 
        }
        //---------------------------------------------
        public void SetConfigMode(uint channel)
        {
            WriteRegister(channel, CANCTRL, 0x87);
        }

    }
}

2013年9月6日 星期五

NETMF Character LCD (C# Code)

I found a usable C# sorec code  for HD44780-compatible Character LCD.
The  BitBucket open source netmf LCD page . has NETMF source code for your projcet.
The online LCD simulator is very useful for you to verify code that you send to LCD.


2013年9月4日 星期三

NETMF C# hardware Watchdog for FEZ Cerb40

Hardware watchdog is very important in industrial control. The FEZ Cerberus main board   /FEZ Cerb40 module are good choose for low cost design. Unfortunately, it is not support watchdog in firmware! (also, The GHI guy said :  Open Source "OSHW" is not support!)

I read the STM32F405 reference manual to find out the solution ... And I try to write the low leve CPU register setting to enable watchdog ...  It is working ! 

The C# source code as follows :
using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHI.OSHW.Hardware.LowLevel;

 class iWatchDog
    {
        public uint  TimeOut = 4000; // default 4000 units    
        private uint AccKey = 0x5555;
        private uint RstKey = 0xAAAA;
        private uint EnableKey = 0xCCCC;
        //----------------------------------------------------------------
        Register IWDG_KR  = new Register(0x40003000);
        Register IWDG_PR  = new Register(0x40003004);
        Register IWDG_RLR = new Register(0x40003008);
        Register IWDG_SR  = new Register(0x4000300C);

        //-----------------------------------------------------------------
        public void Init()
        {
            IWDG_KR.Write(AccKey);   // open the access key
            IWDG_PR.Write(4);        // write the Prescaler for 2ms (One unit)
            IWDG_KR.Write(AccKey);   // open again
            IWDG_RLR.Write(TimeOut); // write the down counter  

        }
        //--------------------------------------------------------------
        public void Enable()
        {
            IWDG_KR.Write(AccKey);    // open access key
            IWDG_KR.Write(EnableKey); // enable counter
        }
        //---------------------------------------------------------------
        public void Reset()
        {
            IWDG_KR.Write(AccKey);    // open access key
            IWDG_KR.Write(RstKey);    // reload counter
        }

    }


//--------------------------------------------
// your main program as follows:
//--------------------------------------------.
.
 iWatchDog Wdog = new iWatchDog();
 Wdog.TimeOut = 2500; // for 5 second time out
 Wdog.Init();
 Wdog.Enable();  // enable watch dog

.
.
//-------- the easy way to reset the watchdos counter -----------------
  void timer500_Tick(GT.Timer timer)// 500mS timer tick
  {


             Wdog.Reset(); // reload the watchdog timeout counter
  }

2013年9月3日 星期二

I2C for EEPROM

The  Cerb Family has one I2C interface that connected to socket1 and socket2. I found a very usable code from GHI Electronics . I test the sorce code for 24LC16 eeprom and it is working.
The source code as follows: 
 
//-------------- setup the I2C device ----------------------
I2CDevice EepI2C = new I2CDevice(new I2CDevice.Configuration(0x50, 400)); // 24LC16 Chip @400KHZ clock

//--------------- Write to EEPROM -----------------------
public void EepWrite(int Address, byte data)
        {
            var xActions = new I2CDevice.I2CTransaction[1];
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { (byte)(Address >> 8), (byte)(Address &                 0xFF),data });
            EepI2C.Execute(xActions, 1000);
            Thread.Sleep(5); // Mandatory after each Write transaction !!!
        }

//----------- Read from EEPROM ----------------------
public byte EepRead(int Address)
        {
            var Data = new byte[1];
            var xActions = new I2CDevice.I2CTransaction[1];
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { (byte)(Address >> 8), (byte)(Address & 0xFF) });
            EepI2C.Execute(xActions, 1000);
            Thread.Sleep(5);   // Mandatory after each Write transaction !!!
            xActions[0] = I2CDevice.CreateReadTransaction(Data);
            EepI2C.Execute(xActions, 1000);
            return Data[0];
        }

2013年9月2日 星期一

NETMF Cpu.Pin / PWM Channel /Analog Channel

A usable reference :
NETMF pin map
Cpu.Pin
Port
Cpu.Pin
Port
Cpu.Pin
Port
0
PA0
32
PC0
64
PE0
1
PA1
33
PC1
65
PE1
2
PA2
34
PC2
66
PE2
3
PA3
35
PC3
67
PE3
4
PA4
36
PC4
68
PE4
5
PA5
37
PC5
69
PE5
6
PA6
38
PC6
70
PE6
7
PA7
39
PC7
71
PE7
8
PA8
40
PC8
72
PE8
9
PA9
41
PC9
 
 
10
PA10
42
PC10
 
 
11
PA11
43
PC11
 
 
12
PA12
44
PC12
 
 
13
PA13
45
PC13
 
 
14
PA14
46
PC14
 
 
15
PA15
47
PC15
 
 
16
PB0
48
PD0
 
 
17
PB1
49
PD1
 
 
18
PB2
50
PD2
 
 
19
PB3
51
PD3
 
 
20
PB4
52
PD4
 
 
21
PB5
53
PD5
 
 
22
PB6
54
PD6
 
 
23
PB7
55
PD7
 
 
24
PB8
56
PD8
 
 
25
PB9
57
PD9
 
 
26
PB10
58
PD10
 
 
27
PB11
59
PD11
 
 
28
PB12
60
PD12
 
 
29
PB13
61
PD13
 
 
30
PB14
62
PD14
 
 
31
PB15
63
PD15
 
 

C# Example:   
LED   = new OutputPort((Cpu.Pin)5, true);  //PA5
// Assign the I/O port PA5 as a output port for LED display.

PWM CHANNEL
Physical Pin
 
ANALOG  CHANNEL
Physical Pin
0
PC6
 
0
PA6
1
PA7
 
1
PA2
2
PC7
 
2
PA3
3
PA8
 
3
PC0
4
PB0
 
4
PC1
5
PB1
 
5
PA4
6
PB5
 
6
PC2
7
PB4
 
7
PC3
8
PB3
 
8
PA5
9
PB11
 
9
PB0
10
PB10
 
10
PB1
11
PA10
 
 
 
12
PA9
 
 
 
13
PA15
 
 
 
14
PB8
 
 
 
15
PB9
 
 
 

C# Example :
 AnalogInput Sensor1 = new AnalogInput(Cpu.AnalogChannel.ANALOG_3);
// Assign the Analog input channel 3 as a Sensor1
  PWM Moto1Pwm = new PWM(Cpu.PWMChannel.PWM_0, 10000, 0.5, false);
// Assign PWM channel 0 as Moto1Pwm output  and working at 10KHz, 50% duty cycle