Code Monkey home page Code Monkey logo

evic-sdk's Introduction

eVic SDK is a software development kit for writing APROMs for the Joyetech eVic VTC Mini.

Setting up the environment

To use evic-sdk, you need a working arm-none-eabi GCC toolchain, binutils and libc. On Linux, most distros have precompiled packages in their repos. For example, on Fedora, install the following packages:

arm-none-eabi-gcc
arm-none-eabi-newlib

On Ubuntu, the following should be enough:

gcc-arm-none-eabi
libnewlib-arm-none-eabi

On OSX you can use brew:

brew tap mpaw/arm-none-eabi
brew update
brew install gcc-arm-none-eabi

On Windows, first install the precompiled ARM toolchain. Choose an installation path without spaces to avoid problems with the build process. If you already have a working Windows make and git along with standard GNU utilities you can go ahead, but make sure those binaries are in your PATH. Otherwise, install Cygwin and add the following packages on top of the base install:

make
git

On any OS, you also need a working python-evic install. If you experience problems with hidapi, you can flash using the official updater. The conversion utilies needed by the SDK will work anyway.

Installing python-evic on Cygwin

On Cygwin, hidapi (needed by python-evic) won't build as-is. There are various issues (Cygwin not recognized as a target, DLL naming conflict, HID open permissions). You have two options: you can install python-evic just for the conversion part which doesn't require hidapi and use the official updater for flashing, or patch hidapi to make it work on Cygwin. In either case, you need to install python-evic in the first place:

  1. Install the following Cygwin packages:

    python3
    python3-setuptools
    
  2. Download and install python-evic:

    git clone https://github.com/Ban3/python-evic
    cd python-evic
    python3 setup.py install
    

If you want to patch hidapi to get flashing functionality from python-evic, follow those instructions:

  1. Install the following Cygwin packages:

    binutils
    gcc-core
    gcc-g++
    libhidapi0
    libhidapi-devel
    libusb1.0
    libusb1.0-devel
    wget
    patch
    
  2. Download, patch and install hidapi:

    wget https://pypi.python.org/packages/source/h/hidapi/hidapi-0.7.99.post12.tar.gz
    wget http://pastebin.com/raw/16E7UdNF && echo >> 16E7UdNF
    tar -zxvf hidapi-0.7.99.post12.tar.gz
    patch -s -p0 < 16E7UdNF
    cd hidapi-0.7.99.post12
    python3 setup.py install
    

Installation

  1. Clone this repository:

    git clone https://github.com/ReservedField/evic-sdk.git
    cd evic-sdk
    
  2. Download the latest M451 series SDK from Nuvoton and copy the Library folder inside evic-sdk/nuvoton-sdk, as to have evic-sdk/nuvoton-sdk/Library.

  3. Point the EVICSDK environment variable to the evic-sdk folder. For example, if you're using bash and are in the SDK directory:

    echo "export EVICSDK=$(pwd)" >> $HOME/.bashrc
    

    Make sure to restart your terminal to ensure variables are set before building.

  4. Build the SDK:

    make
    

Building your first APROM

The helloworld example should be the first thing you try compiling and flashing, to check that everything is working correctly. Build it like:

cd example/helloworld
make

If the build succeeds, you should now have a bin/rel/DEVICE/helloworld.bin file ready to flash. This file is encrypted and compatible with the official updater.

Flashing

You can flash the output binary using the official updater. For development, using python-evic is quicker and simpler:

evic-usb upload bin/rel/DEVICE/helloworld.bin

If everything went well you should see the "Hello, World." message.

This APROM doesn't include USB updating, so you need to reboot to LDROM to flash something else. To do it, remove the battery and disconnect the USB cable. Then, holding the right button, connect the USB cable. Now you can let the button go and flash away. You can also insert the battery while the button is pressed, then let it go and connect the cable. I find powering over USB is more convenient (as long as the APROM doesn't require significant power, i.e. it doesn't fire the atomizer). Similiarly, holding the left button during powerup will force the system to boot from APROM.

Unless you're messing with the LDROM, this is practically unbrickable - you can always boot to LDROM and restore. Actually, APROM update is always done from LDROM: the official APROM reboots to LDROM and flashing happens from there.

The build system

The build system, used both by the SDK and APROMs, works around specifiers. A specifier is a string in the form device-flavor, where device is a supported device and flavor is a build flavor.

Supported devices:

  • evic: Joyetech eVic VTC Mini
  • vtwom: Joyetech eVic VTwo Mini
  • all: all of the above

Build flavors:

  • dbg: debug build
  • rel: release build
  • all: all of the above

See below for the differences between debug and release builds. The all-all specifier is also aliased to all. There are two classes of make targets:

  • specifier: performs a build for the specified device and flavor
  • clean-specifier: cleans the build for the specified device and flavor

Some examples (if more than one command is given, they are alternatives):

# Build everything
make all
make all-all
# Clean everything
make clean-all
make clean-all-all
# Build for eVic VTC Mini, debug flavor
make evic-dbg
# Build for eVic VTC Mini, all flavors
make evic-all
# Clean for eVic VTC Mini, release flavor
make clean-evic-rel
# Build for all devices, release flavor
make all-rel
# Clean for all devices, debug flavor
make clean-all-dbg
# Mix & match
make all-rel evic-dbg

Default targets

While the specifier system lets you specify exactly what you want, it can feel too verbose for day-to-day development. For this reason, the build system accepts two environment variables:

  • EVICSDK_MAKE_DEFAULT_DEVICE: default device(s)
  • EVICSDK_MAKE_DEFAULT_FLAVOR: default flavor(s)

Those can be set to a single device/flavor or to a list of them (for example, default flavors dbg rel and all are the same). You can omit the device, the flavor or both from any specifier and they will be filled in from those variables. Unset or empty variables default to all. The empty target is also aliased to def. Some examples:

# Build for default device(s) and flavor(s)
make
make def
# Clean for default device(s) and flavor(s)
make clean
# Build for default device(s), debug flavor
make dbg
# Build for eVic VTC Mini, default flavor(s)
make evic
# Clean for default devices(s), release flavor
make clean-rel

If you're writing scripts around the build system don't assume the user's defaults and use the full specifiers (unless you actually want to use the user's defaults).

Object files

Objects files for a specific device and flavor live in the obj/FLAVOR/DEVICE directory. The source tree is replicated in there, to avoid conflicts between files with the same name. If you wanted to compile the file src/foo/bar.c for an eVic VTC Mini, debug flavor, you could issue make obj/dbg/evic/src/foo/bar.o.

Source dependency files

Source dependency files live in the same directory as object files. They have a .d extension and are generated automatically when objects are built.

SDK builds

SDK output files live in the lib/FLAVOR/DEVICE directory. Debug builds enable debug info generation from the compiler and a fault handler that will display crash and register info, which can be decoded using the script in tools/fault-decode.

You can generate Doxygen documentation (doc directory) for the SDK using make docs. To clean it use make clean-docs.

APROM builds

APROM output files live in the bin/FLAVOR/DEVICE directory. The standard Makefile for APROMs follows this scheme:

TARGET = helloworld
OBJS = main.o
include $(EVICSDK)/make/Base.mk

TARGET is the base name for outputs. OBJS is a list of objects to be built. Notice that, even though objects live in obj/FLAVOR/DEVICE, the object list is written as if they were in the same directory as the sources. For example, src/foo/bar.c would appear as src/foo/bar.o in the list. This is done so that you can let the build system worry about devices and flavors (and to preserve compatibility with Makefiles written for the old build system). Since the source tree is replicated for the objects, always use relative paths without .. components (you can't have sources at a higher level than the Makefile). Finally, make/Base.mk has to be included (after setting those variables). See the top of make/Base.mk for more variables you can use.

The main output is bin/FLAVOR/DEVICE/TARGET.bin, which is an encrypted binary compatible with the official updater. Debug builds enable debug info generation from the compiler and generate some additional outputs:

  • bin/dbg/DEVICE/TARGET.elf: ELF output from compilation
  • bin/dbg/DEVICE/TARGET_dec.bin: unencrypted binary
  • bin/dbg/DEVICE/TARGET.map: linker map

Also, they are built against the debug SDK, so the fault handler is enabled. All the outputs except the linker map are targets (so you could make bin/dbg/DEVICE/TARGET.elf, for example).

Note that APROMs for a certain device and flavor combination are built against the SDK for that same device and flavor, so you'll need to have that SDK built for it to succeed. If you see linker errors about missing evicsdk-crt0.o, -levicsdk or -lnuvosdk, or you get No SDK found for DEVICE-FLAVOR, chances are you don't have the needed SDK built.

Parallel make

Parallel make (-j option) is supported and works as you would expect. However, problems can arise when you mix build and clean targets. For example, a default rebuild can be performed with make clean && make. For single-threaded make this could be shortened to make clean def, because targets will be made one at a time from left to right. With parallel make you will need to use the full form because the two targets would likely be made concurrently, breaking the build. Of course, mixing multiple build targets or multiple clean targets poses no issues.

Clang support

Clang is supported: just build with CC=clang make. At the moment, the support still depends on arm-none-eabi GCC for some standard headers and libraries. It will also generate a fair amount of warnings for SDK builds. On Cygwin Clang is assumed to be compiled for Cygwin and not for Windows (e.g. downloaded via the Cygwin package manager).

C++ support

C++ is supported, just name your sources with .cpp extensions. The C++ standard library is not supported. Exception handling and RTTI are disabled. It's more like C with classes than C++. You'll need to have arm-none-eabi-g++ installed to compile C++ code (even if you use Clang - we still need GCC's headers).

Legacy clean

If you're migrating from the old build system to the new one you'll probably want to get rid of the old cruft. Aside from running make clean with an old SDK, you can do it manually:

  • For the SDK, remove the lib directory and all .o files (recursively).
  • For APROMs, remove the bin directory and all .o files (recursively).

Misc

The following environment/make variables are available:

  • EVICSDK_MAKE_DEBUG: set to non-empty to enable extra debug output from the build system. Useful when investigating or reporting bugs.
  • EVICSDK_FPU_DISABLE: set to non-empty to disable FPU support and lazy stacking. Needs a full rebuild to avoid mixing FPU and no-FPU objects. Can be useful when debugging very rare, tricky FP bugs. Do not use this unless you fully understand what it means (no, it won't make you binaries smaller or faster, even if you don't use the FPU).

Thread/ISR safety

Unless otherwise specified by the documentation, SDK functions are thread-safe and ISR-safe. A function is thread-safe when it can be used concurrently by multiple threads. ISR-safety, on the other hand, is not strictly about interrupt concurrency: it means that the function can be called from ISR/callback contexts. Don't call non ISR-safe functions from these contexts.

Reporting bugs

I invite you to report bugs using the Issues page. Please confirm the bug against the latest SDK commit and include all information needed to reproduce the bug, like:

  • OS, make/compiler/binutils/newlib versions;
  • Head commit and branch of the SDK you're using;
  • Device and flavor (does it happen in release builds? Debug? Both?);
  • Code (if applicable), preferably reduced to a Minimal, Complete and Verifiable (MCV) example;
  • Things you tried and didn't work;
  • For crashes, the crash dump generated by a debug build;
  • For build system bugs, the debug output (i.e. EVICSDK_MAKE_DEBUG=1 make ...). Try minimizing it: if make evic-dbg is enough to make it happen, don't send output for make all.

Of course if you've already identified the bug in the SDK code you don't need to include as much information. Be sensible and everyone involved will be happy.

Pull requests

Pull requests are welcome. A few rules:

  • Respect the coding and documentation style of the SDK and refer to the tips & tricks.
  • PRs must merge cleanly against the branch they target (preferably rebased on top of the latest head for that branch).
  • No useless commits. Multiple related commits in the same PR are okay, but no merge/revert commits and no "Add foo" "Fix foo" "Fix foo again" stuff. Familiarize yourself with git rebase [-i] and use it.
  • Respect the commit message style (look at the history). The title should tell what the effect of a commit is, not how it does it. Titles should be imperative: "Add foo", not "Adds foo". For non-trivial commits you're welcome to add further technical details in the commit body. Stick to 80 columns per row.
  • If you're fixing a bug reference it in the title. If you're fixing a bug that hasn't been reported yet, create an issue first and reference it in your commit title (you don't need to wait for an answer on the issue - go ahead with the PR).

It is understood that big or complex changes often won't be perfect, no need to worry about it. Again, just use common sense and everything will work out.

USB debugging

The SDK provides a working CDC-compliant USB virtual COM port driver. This allows you to communicate with a computer for debugging purposes. On Linux and Mac it's plug-and-play. On Windows, you have to create an INF file with the virtual COM VID/PID pair to get it to install the driver. An example can be found in the Nuvoton SDK, under SampleCode/StdDriver/USBD_VCOM_SinglePort/Windows Driver.

An example on how to use the port is given in example/usbdebug. You can communicate with it using your favorite serial port terminal. All the line coding parameters (baud rate, parity, stop bits, data bits) are ignored, so you don't need to worry about them.

Tips & tricks

While the SDK does a fairly good job of abstracting the low-level details, you still need to remember that you're coding on an embedded platform. A few tips that might be helpful:

  • You should declare variables shared between threads or with callbacks/interrupts as volatile.
  • Resources are limited: be frugal. Write efficient code.
  • Minimize dynamic memory allocation: all memory not used by data or stack is assigned to heap, but RAM is only 32kB and nobody likes a failed malloc.
  • Declare constant data (such as lookup tables) as const: the compiler will place it in ROM, reducing RAM usage.
  • Prefer siprintf over sprintf, as it produces much smaller binaries by stripping out the floating point printing routines. Of course siprintf doesn't support floating point numbers, so if you need to print them and cannot use a fixed-point representation you'll have to live with the increased binary size.
  • When using floating point variables, prefer float over double, because float has hardware support. Using doubles will pull in some floating point emulation code, making your binaries larger.
  • When using standard floating point functions, prefer the ones with the f suffix: hardware support for floats means faster and smaller binaries. If you use double functions, they'll pull in tons of floating point emulation code.

evic-sdk's People

Contributors

ban3 avatar cmock avatar emilgardis avatar mpaw avatar netman69 avatar noisycat3 avatar reservedfield avatar sebirdman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

evic-sdk's Issues

arm-none-eabi-gcc -v returns something unexpected in arch linux

The version string that is grepped in Base.mk returns gcc version 5.3.0 (Arch Repository) on arch linux.

If you manually do

echo "gcc version 5.3.0 (Arch Repository)" | grep "^gcc version" | awk '{print $$3}'

it returns Repository), but the error that is given shows that the whole gcc version 5.3.0 (Arch Repository) follows. (LIne 3)

arm-none-eabi-gcc -Wall -mcpu=cortex-m4 -mthumb -Os -fdata-sections -ffunction-sections -I/home/localsys/projects/evic-sdk/nuvoton-sdk/Library/CMSIS/Include -I/home/localsys/projects/evic-sdk/nuvoton-sdk/Library/Device/Nuvoton/M451Series/Include -I/home/localsys/projects/evic-sdk/nuvoton-sdk/Library/StdDriver/inc -I/home/localsys/projects/evic-sdk/include -c main.c -o main.o
test -d bin || mkdir bin
arm-none-eabi-ld main.o -L/usr/arm-none-eabi/lib -L/usr/lib/arm-none-eabi/newlib -L/usr/lib/gcc/arm-none-eabi/gcc version 5.3.0 (Arch Repository)  -L/home/localsys/projects/evic-sdk/lib -nostdlib -nostartfiles -T/home/localsys/projects/evic-sdk/linker/linker.ld --gc-sections -o bin/atomizer.elf
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `arm-none-eabi-ld main.o -L/usr/arm-none-eabi/lib -L/usr/lib/arm-none-eabi/newlib -L/usr/lib/gcc/arm-none-eabi/gcc version 5.3.0 (Arch Repository)  -L/home/localsys/projects/evic-sdk/lib -nostdlib -nostartfiles -T/home/localsys/projects/evic-sdk/linker/linker.ld --gc-sections -o bin/atomizer.elf'
/home/localsys/projects/evic-sdk/make/Base.mk:115: recipe for target 'atomizer.elf' failed
make: *** [atomizer.elf] Error 1

Errno 104 while install setup.py

Hi,
I'm trying to set up eVic SDK on Ubuntu in a virtual machine (running windows at work) and I keep on getting errors while trying to run command phython3 setup.py install.
I attache a screenshot to show you the log, maybe it's just a liitle something while connecting to pypi.python.org (the line before error).
evic

eVic VTwo Mini 75W support?

Quick question, does this have native VTwo Mini 75w support? I assume it does but just making sure.

Very awesome project πŸ‘

Where is openevic??

I googled a lot but all the pages have gone. What happend to openevic project??

Atomizer_ReadInfo() issue

When call Atomizer_ReadInfo() and state is power off, for measurement converter started with 1V output. I think it's a lot. If resistance is 0.1 ohm is already 10A current and 10W power. Thin Ni coil heats up if check resistance 2-3 times in second, and it high energy consumption.

Maybe add 2-3 level, start at 0.3-0.5V, if resistance is large - set 1V or more?

Issue with examples/helloworld

Hardware version: 1.02

Tried flashing the example/helloworld with the correct display drivers (SSD1327). Instead of seeing "Hello, world!" I got this.

Any ideas?

Weird siprintf behaviour

I don't know where this happened, but Display_PutText on constant strings seems to be broken. Actually, it's broken in a very weird way. Test case:

#include <stdio.h>
#include <M451Series.h>
#include <Display.h>
#include <Font.h>

int main() {
    char buf[100];

    // Without this line it doesn't work
    siprintf(buf, "whatever");

    Display_PutText(8, 56, "Hello,\nWorld.", FONT_DEJAVU_8PT);
    Display_Update();
}

It seems to crash when removing the siprintf line. Which writes on a buffer that is never used. I'm investigating this, but still have no idea what is happening.

Voltage changes are slooow

Hi,

I'm working on PID control for temperature ATM, and I find that changing the voltage is very slow, especially downwards -- e.g. changing from 4V to 1.8V takes about 1.5 seconds. Going up from 0 to 4V only takes about 0.2 seconds.

I've read #24 and understand it's not a good idea to change the CMR too quickly, but can it be more quick?

Can't build on OSX

I'm having a problem getting the examples built on OSX. I installed all the dependencies and set all the env variables.

➜  helloworld git:(master) βœ— echo $ARMGCC
/Users/marcin/Development/evic/gcc-arm-none-eabi-5.2
➜  helloworld git:(master) βœ— echo $EVICSDK
/Users/marcin/Development/evic/evic-sdk

Doing make in the root directory of the project looks to complete successfully. But trying make from within an examples folder errors out:

➜  helloworld git:(master) βœ— make
mkdir -p bin
arm-none-eabi-ld main.o -L/usr/arm-none-eabi/lib -L/usr/lib/arm-none-eabi/newlib -L/usr/lib/gcc/arm-none-eabi/5.2.1 -L/Users/marcin/Development/evic/evic-sdk/lib -nostdlib -nostartfiles -T/Users/marcin/Development/evic/evic-sdk/linker/linker.ld --gc-sections -o bin/helloworld.elf
arm-none-eabi-ld: cannot find armv7e-m/libgcc.a
arm-none-eabi-ld: cannot find armv7e-m/libc.a
arm-none-eabi-ld: cannot find armv7e-m/libm.a
make: *** [helloworld.elf] Error 1

The files are there though:

➜  armv7e-m pwd
/Users/marcin/Development/evic/gcc-arm-none-eabi-5.2/arm-none-eabi/lib/armv7e-m
➜  armv7e-m ls
aprofile-validation.specs libnosys.a                nosys.specs
aprofile-ve.specs         librdimon.a               pid.specs
cpu-init                  librdimon_nano.a          rdimon-crt0.o
crt0.o                    librdpmon.a               rdimon.specs
fpu                       libstdc++.a               rdpmon-crt0.o
iq80310.specs             libstdc++.a-gdb.py        rdpmon.specs
libc.a                    libstdc++_nano.a          redboot-crt0.o
libc_nano.a               libsupc++.a               redboot-syscalls.o
libg.a                    libsupc++_nano.a          redboot.ld
libg_nano.a               linux-crt0.o              redboot.specs
libgloss-linux.a          linux.specs               softfp
libm.a                    nano.specs

Has anyone gotten this working on OSX?

RTC Problem

Hi man,
at first i really want to thank you for this sdk, it's fucking perfect :D

Okay, so there is my problem. I wanted to add a clock to my program, i used your code from example, edited it and i saw it's count a seconds too fast.
When simple timer have a 120 seconds an RTC have something like 122-123 seconds.
Your clean example works good, but when i add a new PutText it's too fast.

My edited example so you can test it by yourself:

/*
 * This file is part of eVic SDK.
 *
 * eVic SDK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * eVic SDK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with eVic SDK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) 2016 ReservedField
 */

#include <stdio.h>
#include <M451Series.h>
#include <Display.h>
#include <Font.h>
#include <RTCUtils.h>
#include <TimerUtils.h>

volatile uint32_t time;

// Names of weekdays
const char const *weekDays[] = {
    "Sun", "Mon", "Tue", "Wed",
    "Thu", "Fri", "Sat"
};

// Names of months
const char const *months[] = {
    "Jan", "Feb", "Mar", "Apr",
    "May", "Jun", "Jul", "Aug",
    "Sep", "Nov", "Dec"
};

void timerCallback(uint32_t counterIndex) {
    // We use the optional parameter as an index
    // counterIndex is the index in timerCounter
    time++;
}

int main() {
    char buf[100];
    RTCUtils_DateTime_t dateTime;

    // Initialize RTC date/time
    // Wednesday, 4th May 2016, 23:59:00
    dateTime.year      = 16;
    dateTime.month     = 5;
    dateTime.day       = 4;
    dateTime.dayOfWeek = 3;
    dateTime.hour      = 23;
    dateTime.minute    = 59;
    dateTime.second    = 0;
    RTCUtils_SetDateTime(&dateTime);

    time = 0;
    Timer_CreateTimer(1, 1, timerCallback, 1);

    while(1) {
        // Get RTC date/time
        RTCUtils_GetDateTime(&dateTime);

        // Display date/time
        siprintf(buf, "%s %02d\n%s %d\n\n%02d:%02d:%02d",
            weekDays[dateTime.dayOfWeek], dateTime.day,
            months[dateTime.month - 1], 2000 + dateTime.year,
            dateTime.hour, dateTime.minute, dateTime.second);
        Display_Clear();
        Display_PutText(0, 0, buf, FONT_DEJAVU_8PT);
        siprintf(buf, "Time:%d", time);
        Display_PutText(0, 80, buf, FONT_DEJAVU_8PT);
        Display_Update();
    }
}

Am I doing something wrong?

evic-convert: not found

Hi,
First of all great project, thank you !

I'm using a Debian 8, i cloned your repo, followed the installation guide, downloaded http://www.nuvoton.com/opencms/resource-download.jsp?tp_GUID=SW0120140916095112 and copied the Library folder into my evic-sdk/nuvoton-sdk/ folder (which I had to create), exported the sdklocation in my bashrc file and reloaded a new terminal.

The SDK compiled perfectly though while trying to compile the helloworld example (or any other example for that matter), evic-convert seems not to be found and I get the following error :

[evic-dbg] ENC bin/dbg/evic/helloworld.bin
/bin/sh: 1: evic-convert: not found
[path_to_sdk]/evic-sdk/make/Base.mk:140: recipe for target 'bin/dbg/evic/helloworld.bin' failed
make: *** [bin/dbg/evic/helloworld.bin] Error 127

Am I forgetting something or is it a bug ?

Once again, big thanks for that project which actually helped me for choosing my e-cig ;)

Support for eVic VT/Cuboid

Is there any chance that the sdk would ever support other Joyetech mods? I understand that it depends on the hardware and pinouts, but after atomizer support is added maybe other mods could be taken into consideration?

Resitance readings

I have Cubis atomizer, it comes with three heads, SS316 1,05 Ohm, SS316 0,56 Ohm and β€œClapton” 1,56 Ohm. With SS316 coils everything looks fine, they heat in your example code and get back to normal resistance after some time while power off (I can do all temp calculations somehow correct too). However using β€œClapton” looks strange. While power off, resistance value always reads as ~1,75Ohm and while firing it drops to ~1,59Ohm. How to explain such behavior and how come original firmware initially reads correct resistance (~1,56 instead of ~1,75 in our case)?

No atomizer detected after a weak battery

Hi again,

Thanks for taking my "perhaps sometimes stupids" tests into account, but that's right this no detection could be an interesting issue in fact.

So, while testing the weak battery, with a 50% battery, inox 0.7 ohm 316L coil on a Presa 75TC (again, settings are right, shunt resistance at 100), testing at 65W in order to have a real weak battery message with the atomizer example, just after the weak battery state, I got a "NO ATOM" state.

What i'm suspecting is a not perfect test of resistance for the TC coils.

I have done some other tests and I often see a higher base resistance than what I assume to be the real one and while firing from cold, a lower resistance is often shown (not always) : from base res 0.75 to live res 0.68 for instance.
(Of course, the atomizer was plugged cold or battery inserted with cold atomizer plugged)

This could be a hint for this state just after a weak state ?

How to extract data?

Thanks for the awesome work put into this.
I'd like to extract the data of my VIC, especially the number/time of puffs.
Any idea how to do this?
Thanks!

APROM doesn't boot by default

After flashing, the device is reset and the APROM boots correctly. If you power down the device (by removing both battery and USB) and then power it on again it is booted to LDROM, unless you keep the left key pushed.
From my recent LDROM dump I see that it's indeed because of the bootflag located at dataflash[13] (I'm referring to the dataflash exposed over USB - real dataflash doesn't have the first 4 checksum bytes). The values are as follows:
0 - Default to APROM boot
1 - Default to LDROM boot
The updater sets it to 1 to get into LDROM after the reset. The APROM is in charge of setting it back to 0. I will add this in the next commit.

Mistake in README

Steps 4 & 5 should be swapped, as you cannot build the sdk without creating an environment variable. This took me embarrassingly long to figure out.

TODO list

Since it's not as big as it used to, I'm publishing the TODO list for evic-sdk. You can find it on my Gist. I'll try to keep it updated for those that want to follow the progress. If you'd like to help and see something you think you can handle, go for it and contact me if you have doubts.

GDDRAM cleaning & global framebuffer

Right now we have two approaches to GDDRAM cleaning: in my SSD1306 driver, the GDDRAM writing code is duplicated, but no empty framebuffer is allocated (zero bytes are sent out one by one). In Ban3's SSD1327 driver, the GDDRAM writing code is not duplicated, at the cost of allocating a 1kB empty framebuffer on the stack. This code is called at the beginning of an APROM, so there's plenty of RAM and it shouldn't be a problem (I originally wrote the code like that thinking of a RAM-deprived environment). The framebuffer is allocated by the APROM code. The original firmware uses a different strategy: the display library allocates the framebuffer, and the APROM code accesses it through drawing primitives. I think this is a superior solution, since it hides away the framebuffer from the user. Plus it would allow to refactor the GDDRAM cleaning without code duplication and without risking a stack crash (even if it's unlikely).
What do others think?

No rule to make target

I can't compile it on OS X already got python-evic compiled working and tested I don't know whats happening

arm-none-eabi-as -mcpu=cortex-m4 -o src/startup/evicsdk_tag.o src/startup/evicsdk_tag.s
mkdir -p lib
arm-none-eabi-ld -r src/startup/startup.o src/startup/evicsdk_tag.o -o lib/libevicsdk_crt0.o
make: *** No rule to make target /nuvoton-sdk/Library/Device/Nuvoton/M451Series/Source/system_M451Series.o', needed bylibevicsdk.a'. Stop.

Custom firmware data flash handling

In the last few days I looked into getting data flash support for CFWs. I'd like to get feedback from other devs as the two strategies I thought of either waste ROM space or are a total nightmare to implement. I will begin explaining how the data flash works and how it is managed by the OFW (official firmware). This way I'll also have something to copypaste into the dataflash docs when I write them... Warning: long post.

The MCU used in the eVic has a 128kB flash for storing APROM and data. The APROM is always stored at the beginning of the flash, mapped at address zero, and can be updated from LDROM/bootloader. The data flash portion extends from the data flash base address (DFBA) to the end of flash, and can be updated with simple FMC commands. Joyetech sets the DFBA to 0x1E000, so APROM code space is 120kB and data flash is 8kB.

Flash is divided into 2kB pages. This means that the smallest erase size possible is 2kB. Erased flash bits are 1, programmed bits are 0. So 1 bits can be always flipped to zero, but flipping a 0 to 1 requires erasing the whole page. Smallest read/write size is 4 bytes.

The 8kB of data flash are thus divided into 4 pages (let's number them from 0 to 3). They are used by the OFW in a wear-leveling scheme. The actual data flash info is 256 bytes long (the one we get from USB HID is bigger, because it's not a 1-to-1 copy of the real data flash). Pages 0 and 1 are split into 256-byte chunks. Starting with erased pages, each time the info is updated it is written to the next chunk, without erasing the pages. Once the firmware runs out of space, it erases the pages and starts back again. This saves erase cycles, erasing each page only once in 4096 / 256 = 16 updates. Because erased dataflash is just a bunch of FF hex bytes, and the first two words of info can't be both full of FF bytes (we'll see later why), finding the most recent info structure is as simple as reading 8 bytes from the start of each 256-byte chunk, and comparing them with 8 FF bytes. If they match, then that chunk is erased memory, i.e. it's after the most recent one.

Pages 2 and 3 are used for puff/time counts. Puff count and puff time are both 4-byte values. The same wear-leveling method is used, with page 2 storing 512 puff count values and page 3 storing 512 puff time values. Since puffs/time will never be 0xFFFFFFFF, looking for this value will find the end of the most recent count/time. Because the two values grow at the same rate, since they are always both saved at the same time, the firmware finds the number of values in page 2 and uses that also for page 3, assuming it to be the same. This will cause some problems to us.

About the dataflash structure, we are mostly interested in the first 12 bytes:

| Offset |   Size  |       Description       |
|--------|---------|-------------------------|
|   +0   | 4 bytes | Data flash CRC checksum |
|   +4   | 4 bytes |     Hardware version    |
|   +8   | 4 bytes |    Data flash version   |

(while CRC can be anything, hardware version can't be a bunch of FFs - that's why looking for 8 FF bytes works)
Once the firmware is booted, it reads the most recent data flash info and computes its CRC checksum. If it doesn't match the stored checksum, of if the data flash version doesn't match a firmware-dependent value, the data flash info is reset to defaults and written to a new block. The only information that is retained is the hardware version, since it can't be determined by the chip.

With CFWs, I want the programmer to be able to define data flash structures, their size and how many pages to use for each of them as wear leveling. This allows optimal use (i.e. big, not so frequently updated data in one page, another page just for very small but frequently updated data, etc.). The SDK will handle erasing, writing and wear leveling.

If we use the same data flash for CFWs, we want the OFW to reset it if it's flashed, since the CFW will most likely have a different data flash format. This means providing an intentionally invalid checksum, a correct hardware version and, optionally, an invalid data flash version at the beginning of every 256-byte chunk. This can work if the CFW data flash structure is at most 244 bytes (or 248, if neglecting the version field). If it's bigger, it becomes harder to implement and possibly inefficent. Also, it's easy for a size to evenly divide 2048 to get maximum density for wear leveling, while it's more difficult for it to divide 244. Another problem is that page 2 must grow at the same rate, or faster, than page 3, otherwise the OFW won't be able to store puff time correctly since it'll try to to write over non-erased data.

The other solution would be remapping the DFBA, leaving the Joyetech data flash intact and reserving our own space for our own data. The OFW hardcodes the 0x1E000 base address, and always remaps the data flash to that, so this would work fine. The problem is that it wastes 8kB of space. With the latest size optimizations the atomizer sample is just shy of 24kB. Many CFWs could fit into much less than 120kB. By leaving Joye's flash untouched we also guard against them changing the format (even though they're probably done with the eVic).

Another issue common to both strategies is what happens if a CFW is flashed and sets the data flash up a certain way, and then another one with a different data flash layout is flashed. If no versioning or way to distinguish them is adopted, this will lead to crashes. I propose two ways to version data flash:

  • Add a 4-byte header, consisting of a 11-bit structure size and 21-bit magic/version unique number, before each and every structure block in the flash. The size field allows easy traversal even when different blocks are there, allowing a CFW to take up space left over from other CFWs and really minimize erase cycles. The drawback is that this works well for big structures, but has significant overhead for small data sizes (e.g., a 32-bit puff counter would double in size).
  • Add a 4-byte header, consisting of a 32-bit magic/version unique number, to the beginning of data or some other suitable location. If the magic value doesn't match the CFW one, the flash is erased and re-initialized by the CFW. This erases the flash each time a different CFW is flashed, but has much less overhead.

What do others think? What would be the most elegant and efficient way to implement this?

From Buck to Boost

Hello,

First of all, I would like to congratulate all contributors for the job already done, all the basis seems to be almost covered in order to make a fully working firmware !

I'm currently testing in with a Presa 75 (so in my local git, I've set device to W007 and shunt to 100, as in OFW), the atomizer example was working quite well with a 0.7ohm SS316L coil, but as soon as battery go weaker, it stops and reboot ?!?

In the feedback to stabilize the DC/DC, only cycles are tested but never the battery : so buck and boost are not driven according to battery : buck in my opinion should be used only if desired voltage is less or equal to battery voltage and boost only for higher voltages.

With only managing cycles, the transition beetween buck and boost can be brutal and a too high current makes a reboot (I suppose)

I've modified the Amotizer.c in order to take battery into account, and it works.

Does anyone else already have this issue ?

Documentation updates regarding build

Please clarify what is meant under "M451 series SDK" in the README as

  • the linked software page contains no package with either "M451" or "SDK" in its name
  • the M451 pages do not have any SDK downloads and furthermore the M451 does not seem to have integrated USB (wrong series?)

https://github.com/ClockSelect/myevic/blob/master/git_doc_en/howtobuild_en.md tells us to use some M451_Series_BSP_CMSIS_V3.01.001.zip (I found it at "http://forum.nuvoton.com/viewtopic.php?f=11&t=129" )

After that and replacing all instances of 'arm-none-eabi' with 'arm-eabi' (perhaps provide a PREFIX in make files?), the main build with "EVICSDK=. make " went well. But helloworld's
EVICSDK=/tmp/evic-sdk/ make ends with

[evic-dbg] CC  obj/dbg/evic/main.o
[evic-dbg] LD  bin/dbg/evic/helloworld.elf
/home/specing/opt/GNAT/2018-arm-elf/bin/../lib/gcc/arm-eabi/7.3.1/../../../../arm-eabi/lib/thumb/v7e-m/fpv4-sp/hard//libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
/boron.a/gnatmail/sandbox/community/arm-elf-linux64/newlib_bootstrap-c/build/arm-eabi/thumb/v7e-m/fpv4-sp/hard/newlib/libc/reent/../../../../../../../../../src/newlib/libc/reent/sbrkr.c:58: undefined reference to `sbrk'
make: *** [/tmp/evic-sdk//make/Base.mk:121: bin/dbg/evic/helloworld.elf] Error 1

My toolchain does strange things to C libraries, but sbrk is defined by you anyway and that should be preferred by the build scripts, no? (src/startup/sbrk.c)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.