NUSolar ZELDA - PIC32 code. for solar cars.
This project aims to provide basic source code for nascent Solar Car teams that use the Microchip PIC32 for their Battery Protection System, and anything else.
###Prerequisites
-
PIC32
-
MPLAB X IDE ≥ 1.0
-
PICkit 2 or 3
###Installation
-
Clone repository
-
Open and compile projects in MPLAB X
-
Upload binaries to PICs with MPLAB X's IPE
###Usage Turn on boards
NUXX provides a stack-based standard C++ library for embedded systems, C++ interfaces for common circuitry (e.g. digital outputs), class implementations for devices that use these (e.g. LEDs, Buttons, Pedals), C++ interfaces for common communication protocols like CAN, SPI, UART, and 1-Wire, and class implementations for devices that use these (e.g. voltage/current/temperature sensors).
Moreover, due to optimization issues, NUXX also includes classes for our boards.
-
libs/nuxx.X
— Optimized C++ library for microcontroller development. -
libs/nu.X
— C library for microcontroller development, with Object-Oriented-emulation.
An MPLAB compiler bug prevents optimization of any C or C++ main project, so the heavily-optimized library project libs/nuxx.X
contains nearly all board-functionality. Each board's main project simply calls into the corresponding library static "main" function.
-
car_bms_cpp.X
— callsnu::BMS::main()
, detailed below. -
car_driver_controls_cpp.X
— callsnu::DriverControls::main()
, detailed below
-
get_tempSensors.X
— Utility to get 1-wire temperature sensors' serial numbers, to populate the table in the BMS code. -
mppt_can.X
— Utility to tell MPPTs to begin sending data. (On the car, this is done by the BMS) -
mppt_upload.X
— Utility to upload the MPPT.hex
binary blob.
In namespace nu
.
array.hpp
— class nu::Array<typename T, size_t N>
replaces the C++ STL std::vector
, and is an array on the Stack. Array<T,N> foo;
is equivalent to T foo[N];
except that foo
may be passed by value as a C++ reference type. This obviates checking for NULL
pointers, and many calls to alloca
. Warning: copying nu::Array
s will deep-copy their elements.
bitset.hpp
— class nu::Bitset<int N>
represents a collection of N
bits. Can be cast to an unsigned long
. Convenient for iterating over "bitfield structs".
enum.hpp
— class nu::Enum<typename T, int N>
is like nu::Array<T,N>
, except it outputs a number whenever an element is added.
lowpassfilter.hpp
— class nu::LowPassFilter
passes a low-pass filter over input values. Useful for the output of noisy sensors.
stream.hpp
— class nu::OStream
allows easy C++ streaming to devices with <<
. You must finalize OStream output with the nu::end
stream manipulator. All subclasses must implement nu::OStream::puts(const char *)
, to handle all stream output.
param.hpp
— functions to query the clock frequency, in namespace nu::param
.
timer.hpp
— functions for delays, in namespace nu::timer
.
wdt.hpp
— functions to Enable/Disable/Clear the WatchDog timer, in namespace nu::WDT
.
flash.hpp
— UNIMPLEMENTED
pinctl.hpp
— class nu::Pin
wraps setting, clearing, toggling, & reading a pin. nu::DigitalIn
, nu::DigitalOut
, and nu::AnalogIn
specialize digital and analog pins.
can.hpp
— declares namespace nu::can
for CAN communication, with nu::can::Module
and nu::can::Channel
.
can_def.hpp
— autogenerated declarations of CAN packet types. Declared in namespace nu::can::frame
. This file is created/overwritten by generate.py
, which can be modified to define your CAN ID list.
onewire.hpp
— class nu::OneWire
wraps most commands to a OneWire bus. It includes ROM commands (e.g. SEARCH_ROM, MATCH_ROM), and some common Function commands (e.g. READ_SCRATCH).
spi.hpp
— class nu::SPI
wraps all communication with an SPI device.
serial.hpp
— class nu::Serial
wraps all communication with a Serial/UART device.
button.hpp
— a simple digital button, nu::Button
subclasses nu::Pin
.
led.hpp
— a simple digital LED, nu::Led
subclasses nu::Pin
.
nokia5110.hpp
— a small LCD, nu::Nokia5110
subclasses nu::SPI
.
ulcd28pt.hpp
— the SteeringWheel LCD, nu::uLCD28PT
subclasses nu::Serial
ltc6803.hpp
— the voltage sensor, nu::LTC6803
subclasses nu::SPI
.
ds18x20.hpp
— a 1-Wire temperature sensor, nu::DS18X20
subclasses nu::OneWire
.
ad7685.hpp
— a low-voltage ADC, nu::AD7685
subclasses nu::SPI
.
hais.hpp
— the analog HAIS current sensors (e.g. HAIS-50P). As NU uses HAIS-50P in conjunction with the AD7685 ADC, nu::HAIS
subclasses nu::AD7685
.
Board classes are collections of Hardware devices and methods to manipulate them. Each board's main()
method starts the run-loop and never returns. Several NU boards contain an NU32 miniboard, and consequentially their classes subclass nu::Nu32
.
nu32.hpp
— nu::Nu32
is the Nu32 development board. Subclasses MUST call its constructor.
driver_controls.hpp
— the NU driver-controls board. Subclasses nu::Nu32
. Controls pedals & switches, signals, & motor-controller communication.
bms.hpp
— the NU battery management system. Subclasses nu::Nu32
. This BMS uses LTC6803s for voltage, HAIS-50P/AD7685s for current, and DS18B20s for temperature. It controls a battery relay and an array relay.
All microcontroller internal and pin functionality is wrapped. Sensor interfaces are written over our wrappings. Projects utilize these interfaces.
nu32.h
— setup NU32 LEDs and UARTs. Possibly does some ADC initialization.
led.h
— control NU32 LEDs
wdt.h
— wrap enable/disable clearing internal WatchDogTimer. We disable during trips
flash.h
— wrap programming microcontroller flash memory
timer.h
— wrap timer, and delay functions
pinctl.h
— wraps PIC32 pins as NU_PIN.
- declaring, setting digital/analog in/out, reading/setting bits, clearing, toggling.
onewire.h
— Wrap pin-communication with 1-wire pins, on top of pinctl.h
can.h
— Wrap CAN peripheral library: setting up pins, adding channels, TX/RX
serial.h
— Wraps PIC32 UART_MODULE for serial comm
serial_async.h
— Same as above, but somehow async
spi.h
— Wraps SPI functions: declaring SPI pins, setting up, reading, and writing.
button.h
— abstracts declaring buttons, updating value, and checking value
struct btn
holds NU_PIN, and current button value.btn_update(b)
updatesb->debounce
.
ltc6803.h
— SPI Voltage monitoring chip
ad7685.h
— SPI Analog-to-Digital Converter used on the BMS current sensor
nokia5110.h
— SPI LCD.
mcp49x2.h
— SPI Digital-to-Analog Converter (unused)
ds18x20.h
— onewire Temperature sensor
can_all.h
— Define all CAN packets
errorcodes.h
— our error codes
error_reporting.h
— generalized error reporting, to multiple devices
- Attach error reporting devices, broadcast error to all devices
mppt_race.h
— unknown, possibly spam MPPTs with requests
async_io.h
— asynchronously queue messages to circular buffer, ISRs
list.h
— provides doubly linked list
safestring.h
— provides strlcpy
and strlcat
for our Cstrings
crc.h
— cyclic redundancy checks, necessary for network data
hais50p.h
— Convert HAIS-50P (via ad7685.h
) reported voltage to current
byteorder.h
— byteswapping facilities
compiler.h
— our ridiculous aliases to GCC extensions
lock.h
— wrap atomic memory access GCC extensions
nu_types.h
— equally ridiculous "faster to type" aliases to primitive types
utility.h
— BUSY_FOR, CLAIM_PIN, other useful functions
- Includes (inline) arithmetic, bits, data, and preprocessor utility functions. And static assertions
- Includes
stdlib.h
andcompiler.h
minunit.h
— unit testing framework
Use Java-style indentation and braces. For function, struct, and variable names are nu_lowercase_with_underscores
. Class names are PascalCase
. Use struct
keyword instead of class
whenever possible.
For indentation: K&R style is used. For function signatures: Linux style is used. For all public symbols: the Nu__
namespace is used. For structs and enums: Nu__ClassName__EnumName
is used. For functions and variables, Nu__ClassName__lowercase_with_underscores
. For macros are NU_ALL_CAPS
. For example:
static ALWAYSINLINE void
NU_INIT_PIN(struct Nu__Pin *p, IoPortId ltr, u32 num)
{
p->ltr = ltr;
p->num = num;
}
Most interfaces are implemented with X Macros, to emulate object-oriented behaviors like methods and inheritance. Constructors are done with 4 DEFINEs:
struct nu_*
— the struct to be wrapped(NU_)*_INIT
are struct initialization blobs. Set a struct equal to the return value.(NU_)*
which accompany these INITs are full declarations, and make use of the corresponding (NU_)*_INIT(NU_)INIT_*
are function-like, accepting a struct argument and assigning to the struct's members. (unused)
For example:
struct nu_pin
is a struct with fieldsltr
andnum
NU_PIN_INIT(ltr,num)
expands to a struct initializer,{(ltr), (num)}
NU_PIN(name, ltr, num)
is a struct declaration:struct nu_pin name = NU_PIN_INIT(ltr, num)
NU_INIT_PIN(struct nu_pin *p, IoPortId ltr, u32 num)
is just a function.
Error reporting via error_reporting.h
is done with emulated virtual function tables.