A standard for shrinking MCU applications and offloading them to either the N76E003 or the EFM8UB3

2

Comments

  • I'm skim-reading this on a phone so following the nuances of the discussion is tricky but I am working on a range of intelligent peripherals that are based on a single model of a sub £1 chip. The inter - chip comms is going to be I2C....
    'sub £1' is a rather higher price point than being discussed here, which is 74xx/4000 series logic replacement.
    The N76E003 has a 400kHz i2c slave hardware block, so i2c could easily be added as a supported link.
    (The State Logic looks to have 5 states for Slave receiver, and 6 states for slave transmitter mode, so code will be small)

    i2c needs 2 wires, but has an advantage you can clip-on many peripherals to the same bus.
  • jmg wrote: »
    I'm skim-reading this on a phone so following the nuances of the discussion is tricky but I am working on a range of intelligent peripherals that are based on a single model of a sub £1 chip. The inter - chip comms is going to be I2C....
    'sub £1' is a rather higher price point than being discussed here, which is 74xx/4000 series logic replacement.
    The N76E003 has a 400kHz i2c slave hardware block, so i2c could easily be added as a supported link.
    (The State Logic looks to have 5 states for Slave receiver, and 6 states for slave transmitter mode, so code will be small)

    i2c needs 2 wires, but has an advantage you can clip-on many peripherals to the same bus.

    I'd have to agree. The current focus is on a few specific controllers, considered for specific price and capabilities. The target language is C to begin with, but all languages will be considered eventually.

    That said I hope there will be overlap in both this project and yours and that we can help each other.

    Are you using i2c to allow for multiple devices on the same bus?

    @jmg can UART in half duplex can use addressing to reach multiple devices on one wire as well as i2c?
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • ... can UART in half duplex can use addressing to reach multiple devices on one wire as well as i2c?
    Yes, that's the basis of RS485 networking (which uses a twisted wire pair). For more localized signaling, you can just use open-collector drivers on one wire.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • ... can UART in half duplex can use addressing to reach multiple devices on one wire as well as i2c?
    Yes, that's the basis of RS485 networking (which uses a twisted wire pair). For more localized signaling, you can just use open-collector drivers on one wire.

    -Phil

    That is what I thought I had read. Thanks for the info :smile:
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • ...
    @jmg can UART in half duplex can use addressing to reach multiple devices on one wire as well as i2c?
    hmm, yes, certainly, if you wanted.

    The UART has a choice of 8b and 9b modes, (9b is a little less PC friendly, as PC-UARTS cannot quickly wiggle the mark/space parity, unless you buy the EXAR ones that supports 9b native )

    You can easily allocate those 8-9 bits as any address/command mix.

    Perhaps something like
    RB8=1 :: Address_7 bits + 1b Echo
    RB8=0 :: Data payload for Peripheral configuration

    Sent as E.aaaaaaa.RB8
    eg
    1.aaaaaaa.1 - Immediate Echo selected 1 of 128 peripheral from slave aaaaaaa

    0.aaaaaaa.1 - Address Slave aaaaaaa, multi byte command, no echo - follows with cccccccc.0, ddddddd.0, etc

    You do need to set the address value somewhere - it can be compile time, or spare pins, or ADC to 2 resistors, or a mix of these.

    If you want to work with any PC-UART, then you can drop to 8b, and (eg) have a 6 bit address field, or maybe 7b can still be squeezed in via a prefix approach

    1.aaaaaaa - Immediate echo of 1 of 127 peripheral data byte(s)

    1.0000000, 1.aaaaaaa - Command prefix tells all slaves do not echo following next address - command/config info will follow.
    Send any number of 0.ddddddd 7 bit payload config bytes, until terminate with Address token (1.aaaaaaa)

    -or-

    For MCU-networks, we have also used a UART-RING topology. This uses 2 pins on every node, but now address management is simply by physical loop location.

    I call this a twisted-ring, using the 9th bit as an frame edge-flag, and a simple common rule is N bytes after 9b _/= are extracted/replaced, with 9th bit cleared.
    All other bytes are simply passed along.

    Result is first slave removes 4 bytes, and echos 4 byte reply, with 9th bit low, moving the frame edge for NEXT slave along 4 bytes.
    Slaves can be counted/discovered by checking delay effect, and you have a natural integrity check.
    eg Knowing < 50 nodes, 4B each, send 200 bytes 9b=0, then start sending 9b=1. 9 slaves will return 36 bytes echos with 9b=0, and then 37th byte+ has 9b=1
  • Peter JakackiPeter Jakacki Posts: 6,902
    edited December 2017 Vote Up0Vote Down
    If you make the 9th bit normally high for data then it looks like a stop bit and fully compatible with PC UARTs etc. PCs though can still change the 9th bit, except to the PC it's called a parity bit, so it is possible for the PC to address the one-wire network if it really had to.

    However most micros expect the 9th bit to be high when it sees an address and can interrupt the CPU or automatically match and enable it. The state of the 9th bit was an unfortunate design decision at the time but one we need to work in with.

    I don't bother using slow open-collector though as all we are trying to do is to protect I/O pins, not arbitrate, in which case it is easier to add a series resistor, and 100R is sufficiently high enough for that purpose. Some of my early 9th bit network designs were in fire control panels which were quite large so using only single wire was quite useful for this purpose. For anything outside of that and up through the many levels I used RS485. I even had RS485 working in an early graphic elevator display over untwisted fire-proof cable that snaked up and down through the levels and from lift well to lift well, low rise section to high rise section, and to make it work on the one continuous cable I just simply reduced the speed to 19.2k.

    But 9th bit mode doesn't have to be all individual addresses. I use some for global and group addresses where I don't expect a response but they should all listen, and some other codes for network control,

    I2C works well when it it is all very close, it was after all designed for "Inter Integrated Circuit" (IIC which became I2C) operation whereby Philips TV at the time could have subsystems such as the tuner for instance distributed in the same chassis. Nonetheless I have been guilty of running this bus many scores of meters in the distant past :)
    Tachyon Forth - compact, fast, forthwright and interactive
    useforthlogo-s.png
    Tachyon Forth News Blog
    TACHYON DEMONSTRATOR
    Brisbane, Australia
  • Is there a use for a UART modes on this project, given that it's known what the chips will be on both ends of the wire?
    To clarify, several modes of UART, as well as I2C, USB, PWM, and PIC will need to be supported.
    Would this be a better tools with a wide net cast over everything or could it benefit from prioritizing the common or useful modes over any esoteric options?
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • Is there a use for a UART modes on this project, given that it's known what the chips will be on both ends of the wire?
    To clarify, several modes of UART, as well as I2C, USB, PWM, and PIC will need to be supported.
    Would this be a better tools with a wide net cast over everything or could it benefit from prioritizing the common or useful modes over any esoteric options?

    Not sure what you meant by 'UART modes', but the big variables around UART use are
    a) BAUD rate
    b) Bits Sent
    and up a layer
    c) Bytes in transaction

    BAUD rate is quite easy to change, over a very wide range in the N76E003. ie 1MBd, to way down to something no PC can send, but an eyeball might decode ;)
    That's usually a single define, with some range tests if needed for init code.

    Bits Sent is somewhat more structural - 9 bit modes have benefits, especially MCU-MCU, but will not work at top baud speeds from a PC, without a special device selection (EXAR)
    PCs can work well enough to develop and test 9 bit code, using force-parity, as Peter mentions.

    i2c slave is not too large a jump, and N76E003 has i2c Slave HW to 400k Baud.

    USB is quite different, and bumps you into the SiLabs part, but there the 40k code size does open many doors.
    Single-bridge parts usually need ~ 8k of code for a good set of features, so a 40k part could support a number.
    eg UART-Bridge and i2c or SPI Bridge, that appears as 2 COM ports may be possible.


    Not sure what your PWM meant, in peripheral comms-link context, but it would be possible to have a command group to set up PWM Frequency and duty, for LED or Buzzer additions to a keyboard code.
    It would be possible to share pins for LED Drive and keyboard scan, with minor caveats.
    N76E003 has quite comprehensive PWM, so could drive up to 6 Servos, or 6 LEDs with up to 16b setpoints. 10b~8b would give 16kHz~64kHz for DAC use.
    Piezo element drive would also be well supported.
  • ... can UART in half duplex can use addressing to reach multiple devices on one wire as well as i2c?
    Yes, that's the basis of RS485 networking (which uses a twisted wire pair). For more localized signaling, you can just use open-collector drivers on one wire.

    Some years ago I build a small home automation system with PIC16F628 nodes networked using a MAX485 in half duplex. SNAP from http://www.hth.com/snap/ was the protocol used to comunicate between the nodes and a "master" PC. The system is still working, unfortunately I don't know where the sources are buried.
    VT-100 Terminal and Graphics Card for the RC2014 Z80 Computer
  • @macca Sounds like a neat project.

    When I heard SNAP I immediately thought of Subnetwork Access Protocol which also came out in 1998.

    What advantages did your automation system gain by using SNAP over other protocols?
    I see there are a number of error detection methodology, and the line "Requires minimal MCU resources to implement" gets my attention.

    I don't think there is a hardware implementation of this. My reading says TI supports the powerline modem concept with an RS-485 network.

    Do you think this is something worth implementing in software?
    With 8 address bits you can easily address loads of devices on RS-485. What would be the potential gain?
    I think there may be a couple nice features that could be extracted in concept for this project which would likely be the same as the answer(s) to my first question.

    The PIC is out of scope for this project but if you benefited from any specific feature(s), that could be useful here.
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • You don't need a ninth bit for addressable networking. Just use escape sequences to set up the addressing and other coommands. For example, let $10 [DLE] be the escape character. A [DLE] sent by the master device on the network, followed by another character signals the slave devices downstream that the other character is a command or control character. That command could be "A" followed by an address. The slave whose address matches would then "wake up" and communicate with the master device.

    To send a [DLE] as data, just send [DLE] [DLE].

    I've used this technique in several applications.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • What advantages did your automation system gain by using SNAP over other protocols?
    I see there are a number of error detection methodology, and the line "Requires minimal MCU resources to implement" gets my attention.
    Of course, 'minimal' is relative, and often claimed....

    SNAP seems to allocate a SYNC byte value, but takes no efforts to ensure DATA/CRC or command bytes are NOT equal to that value.
    I guess you could add a link monostable for additional sync protection, but they do not mention that ?

    It also has quite high overhead - a single byte payload example, is 9 bytes out, and 8 bytes for ACK/NAK - a bit much for IO/keypad-like peripherals, but OK for wider networks like Home Automation ?


  • mikeologistmikeologist Posts: 337
    edited December 2017 Vote Up0Vote Down
    jmg wrote: »
    It also has quite high overhead - a single byte payload example, is 9 bytes out, and 8 bytes for ACK/NAK - a bit much for IO/keypad-like peripherals, but OK for wider networks like Home Automation ?

    I agree, I think the most to extract from that would be a low-resource feature or two which could be implemented as options in this software. @macca has experience enough to help us identify those features, if any.

    I'm going to take a closer look at the error detection. With either target MCU I think minimal error detection beyond the parity bit may be a necessary option for some high precision applications. It may be as simple as triple sending the data but there are better ways. I'm thinking XOR logic may be used in this option.
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • mikeologistmikeologist Posts: 337
    edited December 2017 Vote Up0Vote Down
    I've prepared a sample of the intended code:
    #include "simpletools.h"                    // So you can use the propeller to program the subMCU
    #include "thincan.h"                        // This Project
    
    enum ic ic_type = N76E003;                  // Specify subMCU by name
    enum port protocol = UART0;                 // Reserves Port0>>Pins6&7 for UART with Propeller
    long baud = 115200;                         // Baud rate
    int bits_sent = 8;                          // Length of single byte
    int bytes_trans = 6;                        // Bytes per transaction 
    int parity = 0;                             // Set parity bit to even
    char buffer[6];                             // Output buffer
    char pins_scan_out[9] = "1111110010000000"; //Define 2D matrix Scan out pins, P0 then P1
    char pins_scan_in[9] =  "0000000001111111"; //Define 2D matrix Scan in pins, P0 then P1
    
    int main_mcu() {                            // Main function of the subMCU 
      while(1) {
        if(scan_2d(&buffer) != 0) {             //On keypress event from scan
          foo();
          //TX here
        }      
      }    
    }
    
    int foo() {                                 //All functions part of main function tree will be passed on to subMCU
      int bar = 0;
      return bar;
    }
    
    int main() {                                //Main function run by the programmer, run once, not included
      print(program_ic());                      //Examine globals, use once to configure subMCU
    }   
    

    I think it could be this simple to program a 2D grid with UART communications.
    You just compile this and run it on your propeller with the subMCU connected on a breadboard or something to program the subMCU. Your results and the subMCU status will print to your console.

    I'm sure I've missed stuff, but what do you all think?
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • So getting back to the the title of your post, what you are kinda proposing as new has always been the standard of the industry that is implemented in a variety of non-standard ways. We don't called these sub-CPUs because we consider them sub-systems which may or may not share a common bus. PC keyboards have done this forever as they have their own micro scanning the keys and communicating bidirectionally with PC, the original method was the easy and simple P2/S clock and data.
    Tachyon Forth - compact, fast, forthwright and interactive
    useforthlogo-s.png
    Tachyon Forth News Blog
    TACHYON DEMONSTRATOR
    Brisbane, Australia
  • So getting back to the the title of your post, what you are kinda proposing as new has always been the standard of the industry that is implemented in a variety of non-standard ways. We don't called these sub-CPUs because we consider them sub-systems which may or may not share a common bus. PC keyboards have done this forever as they have their own micro scanning the keys and communicating bidirectionally with PC, the original method was the easy and simple P2/S clock and data.

    Forgive the keyboard concept. It's just an example. The point is more about the code structure and the benefit of standardizing a few MCUs so propeller users can focus on propeller code. I'll get some use out of it as well.

    Not really proposing it as new. I cited an example and asked if a similar concept existed for propeller.
    Other facilities can be included for all the servos and sensors that propeller users already use allowing them to free up pins, cogs, or both with a minimal effort.
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • mikeologist,
    I'm sure I've missed stuff, but what do you all think?
    What you have said in your code example is that the main() function will run on the Propeller and that the functions main_mcu() and foo() will run on the attached MCU.

    That is an interesting concept.

    The missing part is: How on Earth are you going to make that happen?

    That would require some super compiler/build system that can:

    1) Analyse your source code, somehow recognize the parts that should run on the Propeller and those parts intended run on the attached MCU.

    2) Use different compilers to build binary code form those extracted parts that targets the Propeller and attached MCU.

    3) Probably have more than just two compilers available as the MCU could be of any architecture.

    4) Down load the compiled binaries to the various processors and get them running.

    That is a great idea. I have never seen a system that can do that. It sounds like a lot of work.

    Typically people build systems out of different architecture processors. They have separate source code files for each device. Perhaps in different projects/sub projects. They have customized build systems to invoke the appropriate compilers and other tools for each part.

    All those global variables have to go.

    A common way to get the same source file to compile and build for different machines is to make use of #ifdef. The #ifdef and #if can be used to select which parts of the code are to be used in different places. That works when there are a few little things that need tweaking from platform platform. I can get very messy and make for unreadable code if the is a lot of it going on.
  • @heater
    Thanks, that gives me some great stuff to research for my second go in a bit.
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • Heater. wrote: »
    mikeologist,
    That is an interesting concept.

    The missing part is: How on Earth are you going to make that happen?

    That would require some super compiler/build system that can:

    1) Analyse your source code, somehow recognize the parts that should run on the Propeller and those parts intended run on the attached MCU.

    2) Use different compilers to build binary code form those extracted parts that targets the Propeller and attached MCU.

    3) Probably have more than just two compilers available as the MCU could be of any architecture.

    4) Down load the compiled binaries to the various processors and get them running.

    That is a great idea. I have never seen a system that can do that. It sounds like a lot of work.

    Typically people build systems out of different architecture processors. They have separate source code files for each device. Perhaps in different projects/sub projects. They have customized build systems to invoke the appropriate compilers and other tools for each part.

    All those global variables have to go.

    A common way to get the same source file to compile and build for different machines is to make use of #ifdef. The #ifdef and #if can be used to select which parts of the code are to be used in different places. That works when there are a few little things that need tweaking from platform platform. I can get very messy and make for unreadable code if the is a lot of it going on.

    The more I think about the great questions that you asked the more I realize that I put myself in another quagmire.
    Ultimately what is the goal? - To create an easy to use standard for using multiple types of very inexpensive MCUs with the propeller. I noticed that C and SimpleIDE don't have a place in that goal. If I remove these concepts it becomes quite simple to address all of the above.

    I can just make a relatively dumb python GUI. Just select your target MCU, select a few options, and add any custom code. A little scripting and out pops a C file for that MCU. I can just assemble it as text. A little more scripting and I can have it compiled using the correct compiler and options for each MCU.

    It would also need a spin loader program and a schematic to make any Prop into a programmer.

    It won't happen overnight but this plan removes a lot of my self-imposed obstacles.
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • The same suite could also produce your propeller driver code.
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • tonyp12tonyp12 Posts: 1,873
    edited December 2017 Vote Up0Vote Down
    >main() function will run on the Propeller and that the functions main_mcu() and foo() will run on the attached MCU.

    Sounds similar to how my Cooperative multitasking event machine works,
    Main jumps to task, it don't use the stack between main and the (up to) 32tasks, just a mailbox that I guess you could send over i2c
    outboxid:1 is milliseconds OS_sleep
    outboxid:2 is seconds OS_sleep up to the year 2138
    outboxid:3 still working on 3 to 254 id
    struct taskstruct{
    uint32_t outbox;
    uint32_t inbox1;
    uint32_t inbox2;
    uint32_t inbox3;
    char outboxid;
    char inboxid1;
    char inboxid2;
    char inboxid3;
    char statedo;
    char stateset;
    uint32_t data1;
    uint32_t data2;
    };
    
    Setting up a new task, only require you to add its name to common.h file, nothing else, no code spill over to main.c.
    #include "common.h"
    
    /*   PUT YOUR TASK NAME HERE and also in common.h */
    #define this test_task_name
    
    
    /*   TASK ENTRY   */
    void TASKFUNX (void) {
    if (task[this].stateset){task[this].statedo = task[this].stateset; task[this].stateset = 0;}
    switch (task[this].statedo){
    
    case BOOT: SetEvent(this,START); break;    // all task always run boot state at reset.
    
    case INIT: break;                          // if different from boot state.
    
    case START: OS_sleep(this,500); break      // repeat this 1/2sec as an example, toggle your led etc
    
    case EXIT: 
    default:    break;
    }
    }
    

    TASKFUNX and SetEvent are just macro's
    Had to use define for task names as enum is not precompiled.
    #ifndef SRC_COMMON_H_
    #define SRC_COMMON_H_
    #include "stdint.h"        /* so uint32_t and true&false works */
    
    /***************************************/
    /*  PUT TASK NAMES HERE   0-31 + End   */
    #define test_task_name  0
    #define myother_name    1
    #define TaskListEnd     2
    /***************************************/
    #define SetEvent(TASKn,STATEn)  task[TASKn].stateset = STATEn; eventset |= 1<<TASKn
    
    
    /* MACRO for task function name */
    #define taskname2(x) TaskFunc ## x
    #define taskname1(x) taskname2(x)
    #define TASKFUNX taskname1(this)
    ...
    
  • Oh, and if basic is your thing.... Micromite.

    Yup or the multitasking Bypic.

    This is the direction I have chosen, to complement the Prop.

    I don't care about a coupla quid, my time is valuable.

    PropBASIC ROCKS!
  • Mickster wrote: »
    Oh, and if basic is your thing.... Micromite.

    Yup or the multitasking Bypic.

    This is the direction I have chosen, to complement the Prop.

    I don't care about a coupla quid, my time is valuable.

    Cool stuff. Care to share a project layout and how the multitasking benefited your application, please? That would be a great contribution here :-D
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • @jmg @heater @macca and everyone else too please

    I've been exploring the other potential uses for these MCUs than can benefit the propeller.
    This post focuses on the N76E003
    Here is what I have so far:

    10Base-T Ethernet Transformer

    8/16 bit parallel SRAM controller

    TTL to DB9 by emulating the MAX3232 ic

    16 channel multiplexer by adding a shift bit and 8 transistors, providing 16 outputs on 9 pins, emulating the CD74HC4067M96

    8 bit parallel to UART, which I guess is basically just an 8 Bit Shift Register

    and of course the 2D grid & decoder to UART


    I think building a list of target projects will give me a wider set of requirements and help me structure the overall project.
    What do you think? Is everything on the list possible? What questions do I need to ask and answer? What else can we add to the list to increase the usefulness of the project?
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • I've been exploring the other potential uses for these MCUs than can benefit the propeller.
    This post focuses on the N76E003
    I think building a list of target projects will give me a wider set of requirements and help me structure the overall project.
    What do you think? Is everything on the list possible? What questions do I need to ask and answer? What else can we add to the list to increase the usefulness of the project?

    Comments added
    10Base-T Ethernet Transformer

    Not sure what you mean here - do you mean use the transformer as isolation, on come custom serial link ?
    8/16 bit parallel SRAM controller
    Possible, but the N76E003 is light on pins for this, the N76E616 in TQFP48 has more io, for expansion use.

    TTL to DB9 by emulating the MAX3232 ic

    ? MAX3232 is a RS232 level translator, N76E003 cannot do that, but it can connect to a MAX3232
    16 channel multiplexer by adding a shift bit and 8 transistors, providing 16 outputs on 9 pins, emulating the CD74HC4067M96

    General IO expansion is always good,
    8 bit parallel to UART, which I guess is basically just an 8 Bit Shift Register
    If you mean UART to IO expansion, yes, that plus i2c to IO, would be widely useful.
    I've not tried i2c on N76E003 yet, but the data seems to have good flow charts.

    One very flexible idea, is to do a 'UART-SFR bridge', to allow users to R/W any SFR using address.data pair.
    This can then do any GPIO tasks, as well as enable/configure PWM etc


    and of course the 2D grid & decoder to UART
    Yes, keypad encode is common.

    Best focus is the fastest/simplest code overhead in the host, with smallest pin count.
    In N76E003 + P1 pairing, I think that is 1MBd UART, tho 400kHz i2c is probably close behind.


    I would start with UART Duplex (2 pins) as that is easy to test and highly portable.
    Half-duplex could be supported, and it does save 1 pin, (N76E003 has nice support via UART0PX Serial port 0 pin exchange), but this is trickier to nail down, and is harder to test.


    Also, I'll post below some rough notes I made in talking to a NuTiny-SDK-N76E003 - using FreeBASIC on PC. Needed a couple of magic steps....
    This allows you to test using a PC.

    FreeBASIC PC-Side Test code, for NuTiny-SDK-N76E003 Com port - note: this has some fussy details, not seen on other VCPs, but it can work, and with a good Baud range.
    12M Virtual Baud clock, 16b divider, goes down to ~184 Baud. 1MBd is upper limit of N76E003 chip.
    #include once "windows.bi"
    #include "file.bi"
    
    'Option	Action
    ' 'CSn'	Set the CTS duration (in ms) (n>=0), 0 = turn off, default = 1000
    ' 'DSn'	Set the DSR duration (in ms) (n>=0), 0 = turn off, default = 1000
    ' 'CDn'	Set the Carrier Detect duration (in ms) (n>=0), 0 = turn off
    ' 'OPn'	Set the 'Open Timeout' (in ms) (n>=0), 0 = turn off
    ' 'TBn'	Set the 'Transmit Buffer' size (n>=0), 0 = default, depends on platform
    ' 'RBn'	Set the 'Receive Buffer' size (n>=0), 0 = default, depends on platform
    ' 'RS'	Suppress RTS detection
    ' 'LF'	Communicate in ASCII mode (add LF to every CR) - Win32 doesn't support this one
    ' 'ASC'	same as 'LF'
    ' 'BIN'	The opposite of LF and it'll always work
    ' 'PE'	Enable 'Parity' check
    ' 'DT'	Keep DTR enabled after CLOSE
    ' 'FE'	Discard invalid character on error
    ' 'ME'	Ignore all errors
    ' 'IRn'	IRQ number for COM (only supported (?) on DOS)
    
    'function comcheck(port as string) as integer
    Dim   As HANDLE ch
    '=========================================================================
     '
    Dim As Integer res
    dim as DWORD wb
    Dim As String buff,comport
    Dim com_lpOverlapped As LPOVERLAPPED
    
    Dim As COMMTIMEOUTS ct
    Dim As DCB rDCB 'you'll need to get/setcommstate..
    '
    ' COM4 is SiLabs CP2102N == Sends ONE CHAR OK 
    ' COM5 is Nuvoton VCP == Testing device
    ' COM7 is Nuvoton VCP on XP
    'open com  "COM5:3906,n,8,1,cs0,cd0,ds0,rs" as #1 
    'open com  "COM5:3906,n,8,1,cs0,cd0,ds0,rs,bin" as #1 
    open com  "COM5:3906,n,8,1,ds0,bin" as #1   '_needs_ DS0, or does not work on Nuvoton
    '' Get the windows handle
    ch = cast(HANDLE, Fileattr( 1, fbFileAttrHandle ))
    
    res=GetCommState(ch,@rDCB)
    'this will remain static after Set!
    res=SetCommState(ch,@rDCB) ' can comment ALL the above, and works, until remove this line, then stops working....
    print "SetCommState res:";res 
    
    res=GetCommState(ch,@rDCB)
    'read back 
    print "rDCB DCBlength:        ";rDCB.DCBlength          ' 	DCBlength as DWORD
    print "rDCB BaudRate          ";rDCB.BaudRate           ' 	BaudRate as DWORD
    print "rDCB fBinary           ";rDCB.fBinary            ' 	fBinary : 1 as DWORD
    print "rDCB fParity           ";rDCB.fParity            ' 	fParity : 1 as DWORD
    print "rDCB fOutxCtsFlow      ";rDCB.fOutxCtsFlow       ' 	fOutxCtsFlow : 1 as DWORD
    print "rDCB fOutxDsrFlow      ";rDCB.fOutxDsrFlow       ' 	fOutxDsrFlow : 1 as DWORD
    print "rDCB fDtrControl       ";rDCB.fDtrControl        ' 	fDtrControl : 2 as DWORD
    print "rDCB fDsrSensitivity   ";rDCB.fDsrSensitivity    ' 	fDsrSensitivity : 1 as DWORD
    print "rDCB fTXContinueOnXoff ";rDCB.fTXContinueOnXoff  ' 	fTXContinueOnXoff : 1 as DWORD
    print "rDCB fOutX             ";rDCB.fOutX              ' 	fOutX : 1 as DWORD
    print "rDCB fInX              ";rDCB.fInX               ' 	fInX : 1 as DWORD
    print "rDCB fErrorChar        ";rDCB.fErrorChar         ' 	fErrorChar : 1 as DWORD
    print "rDCB fNull             ";rDCB.fNull              ' 	fNull : 1 as DWORD
    print "rDCB fRtsControl       ";rDCB.fRtsControl        ' 	fRtsControl : 2 as DWORD
    print "rDCB fAbortOnError     ";rDCB.fAbortOnError      ' 	fAbortOnError : 1 as DWORD
    print "rDCB fDummy2           ";rDCB.fDummy2            ' 	fDummy2 : 17 as DWORD
    print "rDCB wReserved         ";rDCB.wReserved          ' 	wReserved as WORD
    print "rDCB XonLim            ";rDCB.XonLim             ' 	XonLim as WORD
    print "rDCB XoffLim           ";rDCB.XoffLim            ' 	XoffLim as WORD
    print "rDCB ByteSize          ";rDCB.ByteSize           ' 	ByteSize as UBYTE
    print "rDCB Parity            ";rDCB.Parity             ' 	Parity as UBYTE
    print "rDCB StopBits          ";rDCB.StopBits           ' 	StopBits as UBYTE
    print "rDCB XonChar           ";rDCB.XonChar            ' 	XonChar as byte
    print "rDCB XoffChar          ";rDCB.XoffChar           ' 	XoffChar as byte
    print "rDCB ErrorChar         ";rDCB.ErrorChar          ' 	ErrorChar as byte
    print "rDCB EofChar           ";rDCB.EofChar            ' 	EofChar as byte
    print "rDCB EvtChar           ";rDCB.EvtChar            ' 	EvtChar as byte
    print "rDCB wReserved1        ";rDCB.wReserved1         ' 	wReserved1 as WORD
    
    ' ~~~~~~~~~~~~~~ Replace fields ~~~~~~~~~~~~~~~~~
    'rDCB.fAbortOnError=1
       'commstate.BaudRate =115200
    'rDCB.BaudRate =3906
    'rDCB.ByteSize =8
    'rDCB.Parity = NOPARITY
    'rDCB.StopBits = ONESTOPBIT
    'rDCB.fBinary = TRUE
    'rDCB.fParity = FALSE
    '
    
    
    #IFDEF Add_Queue_Mask
    res=SetupComm( ch, 1024,128)  ' JG added, no magic effect ?
    print "SetupComm res:";res    'success = non-zero
    'declare function SetupComm(byval hFile as HANDLE, byval dwInQueue as DWORD, byval dwOutQueue as DWORD) as WINBOOL
    
    res=SetCommMask(ch, EV_RXCHAR + EV_TXEMPTY )
    print "SetCommMask res:";res    'success = non-zero
    
    res=GetCommTimeouts(ch,@ct)
    print "GetComm res:";res    'success = non-zero
    '
    ct.ReadIntervalTimeout=0 
    ct.ReadTotalTimeoutMultiplier=0 
    ct.ReadTotalTimeoutConstant=100 
    ct.WriteTotalTimeoutMultiplier=100 'milliseconds allowed for each byte written
    ct.WriteTotalTimeoutConstant=500   '+ milliseconds for total write time
    '
    res=SetCommTimeouts(ch,@ct)
    print "SetComm res:";res    'success = non-zero
    '
    dim as COMSTAT chstat
    dim as DWORD cherrsmask
    ClearCommError(ch,@cherrsmask,@chstat)
    ' declare function ClearCommError(byval hFile as HANDLE, byval lpErrors as LPDWORD, byval lpStat as LPCOMSTAT) as WINBOOL
    
    print "Clear res: ";res
    '
    'c has 
    '		//printf("SetCommState - ");
    '  SetCommState(m_hCOMHandle, &dcb );				
    '		//printf("SetCommMask - ");
    '  SetCommMask(m_hCOMHandle, EV_RXCHAR|EV_TXEMPTY );
    '		//printf("SetupComm - ");
    '  SetupComm( m_hCOMHandle, 1024,128) ;
    'declare function SetupComm(byval hFile as HANDLE, byval dwInQueue as DWORD, byval dwOutQueue as DWORD) as WINBOOL
    '		//printf("PurgeComm - ");
    '  PurgeComm( m_hCOMHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ); 
    
    
    'res=PurgeComm(ch,PURGE_TXCLEAR)'clear Write only
    res=PurgeComm(ch,PURGE_TXABORT + PURGE_RXABORT + PURGE_TXCLEAR + PURGE_RXCLEAR)'JG now same as C code
    print "Purge res: ";res
    #ENDIF ' Add_Queue_Mask
    '
    '
    buff="UUUUU"
    res=WriteFile(_
            ch,_
            strptr(buff),_
            len(buff),_
            @wb,_
            null)
    ' declare function WriteFile(byval hFile as HANDLE, byval lpBuffer as LPCVOID, byval nNumberOfBytesToWrite as DWORD, byval lpNumberOfBytesWritten as LPDWORD, byval lpOverlapped as LPOVERLAPPED) as WINBOOL
            
    'res=1 on success, even if write times outs??
    '
    'in theory this would timeout in 4*100+500 milliseconds
    ' and wb=0
    '
    print "Bytes written:";wb
    'CloseHandle(ch)  
    'sleep
    Close #1            
    sleep
     
    

    I also found we needed at least Nu-Link_Command_Tool_V2.02.6629 for reliable command line links, and I see they now have Revision 2.03.6674 (Released 2017-12-11)
  • jmgjmg Posts: 11,067
    edited December 2017 Vote Up0Vote Down
    jmg wrote: »
    If you mean UART to IO expansion, yes, that plus i2c to IO, would be widely useful.
    I've not tried i2c on N76E003 yet, but the data seems to have good flow charts.

    Following this, Google finds this code, for N76E003.i2c, somewhat format mangled on the Chinese web page I found, but their i2c seems simple enough.
    Code looks to make a 34 byte RAM array and R/W into that, - there is no address fields managed, so mention of "The protocol of I2C is same the "24LC64" is rather loose.
    Seems to NACK when hits 34 limit, then restarts from 0.

    Ideas:
    Some minor tweaks could have this acting like a 24C256, (2 Address bytes), and able to boot a P1 from ~17k of code image. (18k-i2c_Slave overhead)
    The N76E003 has useful ADC and PWM, and once it is i2c P1 connected, that is almost free, so can expand P1 ability.

    eg some address not sent by P1.boot or run, could read/write SFRs for ADC.PWM etc in a i2c-SFR bridge (upper address 0xff perhaps?)

    Trickier, but maybe possible, would be N76E003+SPI_Flash, where code for i2c.24C256 emulation actually reads SPI flash, for much larger code support...


    Slave:
    /* ------------------------------------------------ -------------------------------------------------- ------- */ 
    /* N76E003_i2c_Slave_Web.c from http://bbs.21ic.com/icview-2382616-1-1.html */ 
    /* Copyright (c) 2015 Nuvoton Technology Corp. All rights reserved. */ 
    /* */ 
    /* ------------------------------------------------ -------------------------------------------------- ------- */ 
    
    //************************************************ ************************************************** ********* 
    // Nuvoton Technoledge Corp. 
    // Website: http://www.nuvoton.com 
    // E-Mail: MicroC-8bit@nuvoton.com 
    // Date: May / 1/2015 
    //************************************************ ************************************************** ********* 
    
    //************************************************ ************************************************** ********* 
    // File Function: N76E003 I2C Slave demo code 
    //************************************************ ************************************************** ********* 
    
    #include <stdio.h> 
    #include "N76E003.h" 
    #include "Common.h" 
    #include "Delay.h" 
    #include "SFR_Macro.h" 
    #include "Function_Define.h" 
    
    //************************************************ ************************************************** ********* 
    // N76E885-series I2C slave mode demo code, the Slave address = 0xA4 
    // 
    //  _____________              _____________ 
    // | N76E003 (M) |            | N76E003 (S) | 
    // |         SDA | <--------> | SDA         |
    // | (I2C_Master)|            | (I2C_Slave) | 
    // |         SCL | ---------> | SCL         | 
    // |_____________|            |_____________| 
    // 
    // 
    // The protocol of I2C is same the "24LC64" 
    //************************************************ ************************************************** ********* 
    
    
    #define I2C_CLOCK 13  // JG: [s][/s] not used in Slave
    #define EEPROM_SLA 0xA4 
    
    
    UINT8 data_received [34], data_num = 0; 
    
    // ================================================ ================================================== ====== 
    void I2C_ISR (void) interrupt 6 
    { 
    switch (I2STAT) 
    { 
    case 0x00: 
            STO = 1; 
            break; 
    // Follows Figure 15.9. Flow and Status of Slave Receiver Mode 
    case 0x60: 
            AA = 1; 
            // P3 = 0x60; 
            break; 
    
    case 0x68: 
            P02 = 0; 
            while (1); 
            break; 
    
    case 0x80: 
            // P3 = 0x80; 
            data_received [data_num] = I2DAT; 
            data_num ++; 
            if (data_num == 34) 
              AA = 0; 
            else 
              AA = 1; 
            break; 
    
    case 0x88: 
            // P3 = 0x88; 
            data_received [data_num] = I2DAT; 
            data_num = 0; 
            AA = 1; 
            break; 
    
    case 0xA0: 
            // P3 = 0xA0; 
            AA = 1; 
            break; 
    // Follows Figure 15.10. Flow and Status of Slave Transmitter Mode (mostly)
    case 0xA8: 
            // P3 = 0xA0; 
            I2DAT = data_received [data_num]; 
            data_num ++; 
            AA = 1; 
            break; 
    
    case 0xB8: 
            // P3 = 0xB8; 
            I2DAT = data_received [data_num]; 
            data_num ++; 
            AA = 1; 
            break; 
    
    case 0xC0: 
            AA = 1; 
            break; 
    
    case 0xC8: 
            // P3 = 0xC8; 
            AA = 1; 
            break; 
    } 
    
    SI = 0; 
    while (STO); 
    } 
    
    // ================================================ ================================================== ====== 
    void Init_I2C (void) 
    { 
    P13_Quasi_Mode; // set SCL (P13) is Quasi mode 
    P14_Quasi_Mode; // set SDA (P14) is Quasi mode 
    
    SDA = 1;        // set SDA and SCL pins high 
    SCL = 1; 
    
    set_P0SR_6;     // set SCL (P06) is Schmitt triggered input select. 
    
    set_EI2C;       // enable I2C interrupt by setting IE1 bit 0 
    set_EA; 
    
    I2ADDR = EEPROM_SLA; // define own slave address 
    set_I2CEN;      // enable I2C circuit 
    set_AA; 
    } 
    
    // ================================================ ================================================== ====== 
    void main (void) 
    { 
    
    Set_All_GPIO_Quasi_Mode; 
    
    /* Initial I2C function */ 
    Init_I2C (); // initial I2C circuit 
    
    while (1); 
    /* =================== */ 
    } 
    


    Master: (testing pair)
    /* ------------------------------------------------ -------------------------------------------------- ------- */ 
    /* N76E003_i2c_Master_Web.c from http://bbs.21ic.com/icview-2382616-1-1.html */ 
    /* Copyright (c) 2016 Nuvoton Technology Corp. All rights reserved. */ 
    /* */ 
    /* ------------------------------------------------ -------------------------------------------------- ------- */ 
    
    //************************************************ ************************************************** ********* 
    // Nuvoton Technoledge Corp. 
    // Website: http://www.nuvoton.com 
    // E-Mail: MicroC-8bit@nuvoton.com 
    // Date: Apr / 29/2016 
    //************************************************ ************************************************** ********* 
    
    //************************************************ ************************************************** ********* 
    // File Function: N76E003 I2C master mode demo code, the Slave address = 0xA4 
    // 
    //  _____________              _____________ 
    // | N76E003 (M) |            | N76E003 (S) | 
    // |         SDA | <--------> | SDA         |
    // | (I2C_Master)|            | (I2C_Slave) | 
    // |         SCL | ---------> | SCL         | 
    // |_____________|            |_____________| 
    // 
    // The protocol of I2C is same the "24LC64" 
    //************************************************ ************************************************** ********* 
    
    
    #include <stdio.h> 
    #include "N76E003.h" 
    #include "Common.h" 
    #include "Delay.h" 
    #include "SFR_Macro.h" 
    #include "Function_Define.h" 
    
    #define I2C_CLOCK 13      // JG: Looks to be cut/paste from N76E885, as 22.1184M/(4*(13+1)) = 394971.428  The default N76E003 value is 9, for 16M/(4*(9+1)) = 400000
    
    #define EEPROM_SLA 0xA4 
    #define EEPROM_WR 0 
    #define EEPROM_RD 1 
    #define ERROR_CODE 0x78 
    #define PAGE_SIZE 32 
    
    // ================================================ ================================================== ====== 
    void Init_I2C (void) 
    { 
    // /* Set I2C clock rate */ 
    I2CLK = I2C_CLOCK; 
    
    /* Enable I2C */ 
    set_I2CEN; 
    } 
    // ================================================ ================================================== ====== 
    void I2C_Error (void) 
    { 
    // P3 = I2STAT; 
    // P3 = ERROR_CODE; 
    while (1); 
    } 
    // ================================================ ================================================== ====== 
    void I2C_Process (UINT8 u8DAT) 
    { 
    UINT32 u32Count; 
    
    // ------------------------------------------------ -------------------------------------------- 
    // ---- Page Write ------------------------------------------ ---------------------------------- 
    // ------------------------------------------------ -------------------------------------------- 
    /* Step1 */ 
    set_STA; /* Send Start bit to I2C EEPROM */ 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x08) // Check status value after every step 
     I2C_Error (); 
    
    /* Step2 */ 
    clr_STA; // STA = 0 
    I2DAT = (EEPROM_SLA | EEPROM_WR); 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x18) 
     I2C_Error (); 
    
    /* Step3 */ 
    I2DAT = 0x00; // address high for I2C EEPROM 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x28) 
     I2C_Error (); 
    
    /* Step4 */ 
    I2DAT = 0x00; // address low for I2C EEPROM 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x28) 
     I2C_Error (); 
    
    /* Step5 */ 
    for (u32Count = 0; u32Count <PAGE_SIZE; u32Count ++) 
    { 
    I2DAT = u8DAT; 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x28) 
     I2C_Error (); 
    
    u8DAT = ~ u8DAT; 
    } 
    
    // ------------------------------------------------ -------------------------------------------- 
    // ---- Waitting the ready for I2C write -------------------------------------- ---------------- 
    // ------------------------------------------------ -------------------------------------------- 
    /* Step6 */ 
    do { 
    set_STO; 
    clr_SI; 
    
    set_STA; // Check if no ACK is returned by EEPROM, it is under timed-write cycle 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x08) // Check status value after every step 
    I2C_Error (); 
    
    clr_STA; 
    I2DAT = (EEPROM_SLA | EEPROM_WR); 
    clr_SI; 
    while (! SI); // Check SI set or not 
    } while (I2STAT! = 0x18); 
    
    /* Step7 */ 
    set_STO; 
    clr_SI; 
    while (STO); /* Check STOP signal */ 
    // ------------------------------------------------ -------------------------------------------- 
    // ---- Page Read ------------------------------------------ ---------------------------------- 
    // ------------------------------------------------ -------------------------------------------- 
    /* Step8 */ 
    set_STA; 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x08) // Check status value after every step 
     I2C_Error (); 
    
    /* Step9 */ 
    I2DAT = (EEPROM_SLA | EEPROM_WR); 
    clr_STA; 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x18) 
     I2C_Error (); 
    
    /* Step10 */ 
    I2DAT = 0x00; // address high for I2C EEPROM 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x28) 
     I2C_Error (); 
    
    /* Step11 */ 
    I2DAT = 0x00; // address low for I2C EEPROM 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x28) 
     I2C_Error (); 
    
    /* Step12 */ 
    /* Repeated START */ 
    set_STA; 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x10) // Check status value after every step 
     I2C_Error (); 
    
    /* Step13 */ 
    clr_STA; // STA needs to be cleared after START codition is generated 
    I2DAT = (EEPROM_SLA | EEPROM_RD); 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x40) 
     I2C_Error (); 
    
    /* Step14 */ 
    for (u32Count = 0; u32Count <PAGE_SIZE-1; u32Count ++) 
    { 
    set_AA; 
    clr_SI; 
    while (! SI); // Check SI set or not 
    
    if (I2STAT! = 0x50) 
    I2C_Error (); 
    
    if (I2DAT! = u8DAT) 
    I2C_Error (); 
    u8DAT = ~ u8DAT; 
    } 
    
    /* Step15 */ 
    clr_AA; 
    clr_SI; 
    while (! SI); // Check SI set or not 
    if (I2STAT! = 0x58) 
     I2C_Error (); 
    
    /* Step16 */ 
    set_STO; 
    clr_SI; 
    while (STO); /* Check STOP signal */ 
    } 
    // ================================================ ================================================== ====== 
    void main (void) 
    { 
    /* Note 
    MCU power on system clock is HIRC (22.1184 MHz), so Fsys = 22.1184 MHz  (jg: true for N76E885, N76E003 is 16MHz)
    */ 
    
    Set_All_GPIO_Quasi_Mode; 
    Init_I2C ();         // initial I2C circuit 
    I2C_Process (0x55);  /* I2C Master will send 0x55, 0xAA, .... to slave */ 
    
    P0 = 0x00; 
    P3 = 0x00; 
    
    while (1); 
    /* =================== */ 
    } 
    


    Addit:
    Another link on the Nuvoton website leads to
    https://github.com/OpenNuvoton/NuMicro-8051-Family/blob/master/README.md
    with code in both IAR and Keil - for casual users, the IAR demo sounds better : 4k vs 2k code size, and no code-offsets.

    The SiLabs toolchain, has a full version of Keil compiler (no low code limits).

    There is also SDCC compiler : http://sdcc.sourceforge.net/index.php#News
  • I bought 10 of these to play around with. Part of my pile of tiny christmas presents that I bought for myself this year.
    jmg wrote: »
    10Base-T Ethernet Transformer

    Not sure what you mean here - do you mean use the transformer as isolation, on come custom serial link ?
    I want to emulate the ENC28J60
    8/16 bit parallel SRAM controller
    Possible, but the N76E003 is light on pins for this, the N76E616 in TQFP48 has more io, for expansion use.
    This is true, my plan is to use the MCU only for the address and control pins. This will allow me to address quite a few modules with the 003.
    I agree that the same function should be made for the 616 as well. I think the user should have the option to specify their needs and the software will select the minimum chip to meet the specs and provide the finished program and driver software all in one shot.

    TTL to DB9 by emulating the MAX3232 ic

    ? MAX3232 is a RS232 level translator, N76E003 cannot do that, but it can connect to a MAX3232
    I was expecting to hit at least one snag in this list. The MAX3232 is cheap enough that adding anything to the N76E003 is not financially viable,
    but the question is, can we gain a benefit by connecting one to a MAX3232?
    16 channel multiplexer by adding a shift bit and 8 transistors, providing 16 outputs on 9 pins, emulating the CD74HC4067M96

    General IO expansion is always good,
    8 bit parallel to UART, which I guess is basically just an 8 Bit Shift Register
    If you mean UART to IO expansion, yes, that plus i2c to IO, would be widely useful.
    I've not tried i2c on N76E003 yet, but the data seems to have good flow charts.

    One very flexible idea, is to do a 'UART-SFR bridge', to allow users to R/W any SFR using address.data pair.
    This can then do any GPIO tasks, as well as enable/configure PWM etc
    I like this the best as it covers all of GPIO tasks above.

    and of course the 2D grid & decoder to UART
    Yes, keypad encode is common.
    I really like the idea of a decoded character output buffer. As you and Peter put it I can just drop the pin and collect the data.

    Best focus is the fastest/simplest code overhead in the host, with smallest pin count.
    In N76E003 + P1 pairing, I think that is 1MBd UART, tho 400kHz i2c is probably close behind.
    I would like to include all protocols that make sense, potentially including 4/8 bit parallel as well. The first focus for any project should be UART though.


    I would start with UART Duplex (2 pins) as that is easy to test and highly portable.
    Half-duplex could be supported, and it does save 1 pin, (N76E003 has nice support via UART0PX Serial port 0 pin exchange), but this is trickier to nail down, and is harder to test.


    Also, I'll post below some rough notes I made in talking to a NuTiny-SDK-N76E003 - using FreeBASIC on PC. Needed a couple of magic steps....
    This allows you to test using a PC.

    FreeBASIC PC-Side Test code, for NuTiny-SDK-N76E003 Com port - note: this has some fussy details, not seen on other VCPs, but it can work, and with a good Baud range.
    12M Virtual Baud clock, 16b divider, goes down to ~184 Baud. 1MBd is upper limit of N76E003 chip.
    #include once "windows.bi"
    #include "file.bi"
    
    'Option	Action
    ' 'CSn'	Set the CTS duration (in ms) (n>=0), 0 = turn off, default = 1000
    ' 'DSn'	Set the DSR duration (in ms) (n>=0), 0 = turn off, default = 1000
    ' 'CDn'	Set the Carrier Detect duration (in ms) (n>=0), 0 = turn off
    ' 'OPn'	Set the 'Open Timeout' (in ms) (n>=0), 0 = turn off
    ' 'TBn'	Set the 'Transmit Buffer' size (n>=0), 0 = default, depends on platform
    ' 'RBn'	Set the 'Receive Buffer' size (n>=0), 0 = default, depends on platform
    ' 'RS'	Suppress RTS detection
    ' 'LF'	Communicate in ASCII mode (add LF to every CR) - Win32 doesn't support this one
    ' 'ASC'	same as 'LF'
    ' 'BIN'	The opposite of LF and it'll always work
    ' 'PE'	Enable 'Parity' check
    ' 'DT'	Keep DTR enabled after CLOSE
    ' 'FE'	Discard invalid character on error
    ' 'ME'	Ignore all errors
    ' 'IRn'	IRQ number for COM (only supported (?) on DOS)
    
    'function comcheck(port as string) as integer
    Dim   As HANDLE ch
    '=========================================================================
     '
    Dim As Integer res
    dim as DWORD wb
    Dim As String buff,comport
    Dim com_lpOverlapped As LPOVERLAPPED
    
    Dim As COMMTIMEOUTS ct
    Dim As DCB rDCB 'you'll need to get/setcommstate..
    '
    ' COM4 is SiLabs CP2102N == Sends ONE CHAR OK 
    ' COM5 is Nuvoton VCP == Testing device
    ' COM7 is Nuvoton VCP on XP
    'open com  "COM5:3906,n,8,1,cs0,cd0,ds0,rs" as #1 
    'open com  "COM5:3906,n,8,1,cs0,cd0,ds0,rs,bin" as #1 
    open com  "COM5:3906,n,8,1,ds0,bin" as #1   '_needs_ DS0, or does not work on Nuvoton
    '' Get the windows handle
    ch = cast(HANDLE, Fileattr( 1, fbFileAttrHandle ))
    
    res=GetCommState(ch,@rDCB)
    'this will remain static after Set!
    res=SetCommState(ch,@rDCB) ' can comment ALL the above, and works, until remove this line, then stops working....
    print "SetCommState res:";res 
    
    res=GetCommState(ch,@rDCB)
    'read back 
    print "rDCB DCBlength:        ";rDCB.DCBlength          ' 	DCBlength as DWORD
    print "rDCB BaudRate          ";rDCB.BaudRate           ' 	BaudRate as DWORD
    print "rDCB fBinary           ";rDCB.fBinary            ' 	fBinary : 1 as DWORD
    print "rDCB fParity           ";rDCB.fParity            ' 	fParity : 1 as DWORD
    print "rDCB fOutxCtsFlow      ";rDCB.fOutxCtsFlow       ' 	fOutxCtsFlow : 1 as DWORD
    print "rDCB fOutxDsrFlow      ";rDCB.fOutxDsrFlow       ' 	fOutxDsrFlow : 1 as DWORD
    print "rDCB fDtrControl       ";rDCB.fDtrControl        ' 	fDtrControl : 2 as DWORD
    print "rDCB fDsrSensitivity   ";rDCB.fDsrSensitivity    ' 	fDsrSensitivity : 1 as DWORD
    print "rDCB fTXContinueOnXoff ";rDCB.fTXContinueOnXoff  ' 	fTXContinueOnXoff : 1 as DWORD
    print "rDCB fOutX             ";rDCB.fOutX              ' 	fOutX : 1 as DWORD
    print "rDCB fInX              ";rDCB.fInX               ' 	fInX : 1 as DWORD
    print "rDCB fErrorChar        ";rDCB.fErrorChar         ' 	fErrorChar : 1 as DWORD
    print "rDCB fNull             ";rDCB.fNull              ' 	fNull : 1 as DWORD
    print "rDCB fRtsControl       ";rDCB.fRtsControl        ' 	fRtsControl : 2 as DWORD
    print "rDCB fAbortOnError     ";rDCB.fAbortOnError      ' 	fAbortOnError : 1 as DWORD
    print "rDCB fDummy2           ";rDCB.fDummy2            ' 	fDummy2 : 17 as DWORD
    print "rDCB wReserved         ";rDCB.wReserved          ' 	wReserved as WORD
    print "rDCB XonLim            ";rDCB.XonLim             ' 	XonLim as WORD
    print "rDCB XoffLim           ";rDCB.XoffLim            ' 	XoffLim as WORD
    print "rDCB ByteSize          ";rDCB.ByteSize           ' 	ByteSize as UBYTE
    print "rDCB Parity            ";rDCB.Parity             ' 	Parity as UBYTE
    print "rDCB StopBits          ";rDCB.StopBits           ' 	StopBits as UBYTE
    print "rDCB XonChar           ";rDCB.XonChar            ' 	XonChar as byte
    print "rDCB XoffChar          ";rDCB.XoffChar           ' 	XoffChar as byte
    print "rDCB ErrorChar         ";rDCB.ErrorChar          ' 	ErrorChar as byte
    print "rDCB EofChar           ";rDCB.EofChar            ' 	EofChar as byte
    print "rDCB EvtChar           ";rDCB.EvtChar            ' 	EvtChar as byte
    print "rDCB wReserved1        ";rDCB.wReserved1         ' 	wReserved1 as WORD
    
    ' ~~~~~~~~~~~~~~ Replace fields ~~~~~~~~~~~~~~~~~
    'rDCB.fAbortOnError=1
       'commstate.BaudRate =115200
    'rDCB.BaudRate =3906
    'rDCB.ByteSize =8
    'rDCB.Parity = NOPARITY
    'rDCB.StopBits = ONESTOPBIT
    'rDCB.fBinary = TRUE
    'rDCB.fParity = FALSE
    '
    
    
    #IFDEF Add_Queue_Mask
    res=SetupComm( ch, 1024,128)  ' JG added, no magic effect ?
    print "SetupComm res:";res    'success = non-zero
    'declare function SetupComm(byval hFile as HANDLE, byval dwInQueue as DWORD, byval dwOutQueue as DWORD) as WINBOOL
    
    res=SetCommMask(ch, EV_RXCHAR + EV_TXEMPTY )
    print "SetCommMask res:";res    'success = non-zero
    
    res=GetCommTimeouts(ch,@ct)
    print "GetComm res:";res    'success = non-zero
    '
    ct.ReadIntervalTimeout=0 
    ct.ReadTotalTimeoutMultiplier=0 
    ct.ReadTotalTimeoutConstant=100 
    ct.WriteTotalTimeoutMultiplier=100 'milliseconds allowed for each byte written
    ct.WriteTotalTimeoutConstant=500   '+ milliseconds for total write time
    '
    res=SetCommTimeouts(ch,@ct)
    print "SetComm res:";res    'success = non-zero
    '
    dim as COMSTAT chstat
    dim as DWORD cherrsmask
    ClearCommError(ch,@cherrsmask,@chstat)
    ' declare function ClearCommError(byval hFile as HANDLE, byval lpErrors as LPDWORD, byval lpStat as LPCOMSTAT) as WINBOOL
    
    print "Clear res: ";res
    '
    'c has 
    '		//printf("SetCommState - ");
    '  SetCommState(m_hCOMHandle, &dcb );				
    '		//printf("SetCommMask - ");
    '  SetCommMask(m_hCOMHandle, EV_RXCHAR|EV_TXEMPTY );
    '		//printf("SetupComm - ");
    '  SetupComm( m_hCOMHandle, 1024,128) ;
    'declare function SetupComm(byval hFile as HANDLE, byval dwInQueue as DWORD, byval dwOutQueue as DWORD) as WINBOOL
    '		//printf("PurgeComm - ");
    '  PurgeComm( m_hCOMHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ); 
    
    
    'res=PurgeComm(ch,PURGE_TXCLEAR)'clear Write only
    res=PurgeComm(ch,PURGE_TXABORT + PURGE_RXABORT + PURGE_TXCLEAR + PURGE_RXCLEAR)'JG now same as C code
    print "Purge res: ";res
    #ENDIF ' Add_Queue_Mask
    '
    '
    buff="UUUUU"
    res=WriteFile(_
            ch,_
            strptr(buff),_
            len(buff),_
            @wb,_
            null)
    ' declare function WriteFile(byval hFile as HANDLE, byval lpBuffer as LPCVOID, byval nNumberOfBytesToWrite as DWORD, byval lpNumberOfBytesWritten as LPDWORD, byval lpOverlapped as LPOVERLAPPED) as WINBOOL
            
    'res=1 on success, even if write times outs??
    '
    'in theory this would timeout in 4*100+500 milliseconds
    ' and wb=0
    '
    print "Bytes written:";wb
    'CloseHandle(ch)  
    'sleep
    Close #1            
    sleep
     
    

    I also found we needed at least Nu-Link_Command_Tool_V2.02.6629 for reliable command line links, and I see they now have Revision 2.03.6674 (Released 2017-12-11)
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • Ideas:
    Some minor tweaks could have this acting like a 24C256, (2 Address bytes), and able to boot a P1 from ~17k of code image. (18k-i2c_Slave overhead)
    The N76E003 has useful ADC and PWM, and once it is i2c P1 connected, that is almost free, so can expand P1 ability.

    eg some address not sent by P1.boot or run, could read/write SFRs for ADC.PWM etc in a i2c-SFR bridge (upper address 0xff perhaps?)

    Trickier, but maybe possible, would be N76E003+SPI_Flash, where code for i2c.24C256 emulation actually reads SPI flash, for much larger code support...

    I think a lot of people would be happy if we made this. I could certainly use it :smile:
    Any com port in a storm.
    Floating point numbers will be our downfall; count on it.
    Imagine a world without hypothetical situations.
  • The problem I found with trying to do any kind of "universal" solution is that it is all very good and well if it were a chip available in DIP as well as SMD, preprogrammed, and available from most suppliers very cheap. Internally with my own designs I don't have any problems with designing my special peripheral micros onto a board and having programming pads/vias/headers to Flash them with etc.

    However I was very confused with your post because I think you are confused about this area of technology. I didn't know where to start to reply since the actual statements are incorrect or too open-ended.
    Tachyon Forth - compact, fast, forthwright and interactive
    useforthlogo-s.png
    Tachyon Forth News Blog
    TACHYON DEMONSTRATOR
    Brisbane, Australia
  • I bought 10 of these to play around with. Part of my pile of tiny christmas presents that I bought for myself this year.

    Interesting little break-out board. Even has a 3v3 regulator, not mandatory on N76E003 as it runs just fine on USB-5V, but useful for Rasp-Pi or P1 testing where you want 3v3.


Sign In or Register to comment.