Merge branch 'essential-libs'
This commit is contained in:
commit
521f3f495a
64
source/shoh/src/peripherals/DigitalIoPin.cpp
Normal file
64
source/shoh/src/peripherals/DigitalIoPin.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* DigitalIoPin.cpp
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2022
|
||||||
|
* Author: Vasily Davydov
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DigitalIoPin.h"
|
||||||
|
|
||||||
|
DigitalIoPin::DigitalIoPin (int port, int pin, bool input, bool pullup,
|
||||||
|
bool invert)
|
||||||
|
{
|
||||||
|
assert ((port <= UINT8_MAX_VALUE) && (pin <= UINT8_MAX_VALUE));
|
||||||
|
_io._port = (uint8_t)port;
|
||||||
|
_io._pin = (uint8_t)pin;
|
||||||
|
_io._input = input;
|
||||||
|
_io._pullup = pullup;
|
||||||
|
_io._invert = invert;
|
||||||
|
_io.IOCON_mode = IOCON_MODE_INACT;
|
||||||
|
_io.IOCON_inv = IOCON_FUNC0;
|
||||||
|
setIoPin ();
|
||||||
|
}
|
||||||
|
|
||||||
|
DigitalIoPin::~DigitalIoPin ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DigitalIoPin::setIoPin ()
|
||||||
|
{
|
||||||
|
bool direction = true;
|
||||||
|
if (_io._input)
|
||||||
|
{
|
||||||
|
direction = false;
|
||||||
|
_io.IOCON_mode = IOCON_MODE_PULLUP;
|
||||||
|
if (!_io._pullup)
|
||||||
|
{
|
||||||
|
_io.IOCON_mode = IOCON_MODE_PULLDOWN;
|
||||||
|
}
|
||||||
|
if (_io._invert)
|
||||||
|
{
|
||||||
|
_io.IOCON_inv = IOCON_INV_EN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Chip_IOCON_PinMuxSet (LPC_IOCON, _io._port, _io._pin,
|
||||||
|
(_io.IOCON_mode | _io.DigitalEn | _io.IOCON_inv));
|
||||||
|
/** False direction equals input */
|
||||||
|
Chip_GPIO_SetPinDIR (LPC_GPIO, _io._port, _io._pin, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DigitalIoPin::read ()
|
||||||
|
{
|
||||||
|
bool state = (Chip_GPIO_GetPinState (LPC_GPIO, _io._port, _io._pin));
|
||||||
|
return (_io._invert && !_io._input) ? !state : state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DigitalIoPin::write (bool value)
|
||||||
|
{
|
||||||
|
assert (!(_io._input));
|
||||||
|
Chip_GPIO_SetPinState (LPC_GPIO, _io._port, _io._pin, ((_io._invert) ? !value : value));
|
||||||
|
}
|
||||||
|
|
||||||
43
source/shoh/src/peripherals/DigitalIoPin.h
Normal file
43
source/shoh/src/peripherals/DigitalIoPin.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* DigitalIoPin.h
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2022
|
||||||
|
* Author: Vasily Davydov
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DIGITALIOPIN_H_
|
||||||
|
#define DIGITALIOPIN_H_
|
||||||
|
|
||||||
|
#define UINT8_MAX_VALUE 255
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <chip.h>
|
||||||
|
|
||||||
|
typedef struct DigitalIOConfigStruct
|
||||||
|
{
|
||||||
|
uint8_t _port;
|
||||||
|
uint8_t _pin;
|
||||||
|
bool _input;
|
||||||
|
bool _pullup;
|
||||||
|
bool _invert;
|
||||||
|
uint32_t IOCON_mode;
|
||||||
|
uint32_t IOCON_inv;
|
||||||
|
uint32_t DigitalEn;
|
||||||
|
} DigitalIOConfigStruct;
|
||||||
|
|
||||||
|
class DigitalIoPin
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DigitalIoPin (int port, int pin, bool input = true, bool pullup = true,
|
||||||
|
bool invert = false);
|
||||||
|
DigitalIoPin (const DigitalIoPin &) = delete;
|
||||||
|
virtual ~DigitalIoPin ();
|
||||||
|
bool read ();
|
||||||
|
void write (bool value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DigitalIOConfigStruct _io = { 0, 0, false, false, false, 0, 0, IOCON_DIGMODE_EN};
|
||||||
|
void setIoPin ();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DIGITALIOPIN_H_ */
|
||||||
95
source/shoh/src/peripherals/EEPROMWrapper.cpp
Normal file
95
source/shoh/src/peripherals/EEPROMWrapper.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* EEPROMWrapper.cpp
|
||||||
|
*
|
||||||
|
* Created on: Dec 4, 2022
|
||||||
|
* Author: tylen
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <EEPROMWrapper.h>
|
||||||
|
|
||||||
|
EEPROM_Wrapper::EEPROM_Wrapper ()
|
||||||
|
{
|
||||||
|
/* Enable EEPROM clock and reset EEPROM controller */
|
||||||
|
Chip_Clock_EnablePeriphClock (SYSCTL_CLOCK_EEPROM);
|
||||||
|
Chip_SYSCTL_PeriphReset (RESET_EEPROM);
|
||||||
|
iap_exec = reinterpret_cast<IAP_call> (IAP_ENTRY_LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
EEPROM_Wrapper::~EEPROM_Wrapper ()
|
||||||
|
{
|
||||||
|
// TODO Auto-generated destructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
e_memcpy (void *from, void *to, unsigned int n)
|
||||||
|
{
|
||||||
|
if (!from)
|
||||||
|
return;
|
||||||
|
char *source = (char *)from;
|
||||||
|
char *dest = (char *)to;
|
||||||
|
while (n)
|
||||||
|
{
|
||||||
|
(*dest++) = (*source++);
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EEPROM_Wrapper::eeprom_execute (EEPROM *rom)
|
||||||
|
{
|
||||||
|
command[0] = rom->mode;
|
||||||
|
command[1] = rom->addr;
|
||||||
|
command[2] = rom->data;
|
||||||
|
command[3] = rom->size;
|
||||||
|
command[4] = rom->clock;
|
||||||
|
this->iap_exec (command, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EEPROM_Wrapper::eeprom_use (uint8_t *data, uint32_t addr, uint32_t size,
|
||||||
|
bool mode)
|
||||||
|
{
|
||||||
|
rom.addr = addr;
|
||||||
|
rom.data = (uint32_t)data;
|
||||||
|
rom.mode = (mode) ? IAP_EEPROM_READ : IAP_EEPROM_WRITE;
|
||||||
|
rom.size = size;
|
||||||
|
#if INCLUDE_vTaskSuspend
|
||||||
|
vTaskSuspendAll ();
|
||||||
|
#endif
|
||||||
|
/* Main execution of eeprom r/w */
|
||||||
|
eeprom_execute (&rom);
|
||||||
|
#if INCLUDE_vTaskSuspend
|
||||||
|
xTaskResumeAll ();
|
||||||
|
#endif
|
||||||
|
assert (result[0] == IAP_CMD_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
EEPROM_Wrapper::str_read_from (uint32_t addr, uint32_t amount)
|
||||||
|
{
|
||||||
|
eeprom_use (buffer, addr, amount, READ);
|
||||||
|
std::string str = (char *)buffer;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EEPROM_Wrapper::write_to (uint32_t addr, std::string str)
|
||||||
|
{
|
||||||
|
std::copy (str.begin (), str.end (), std::begin (buffer));
|
||||||
|
eeprom_use (buffer, addr, str.length (), WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
EEPROM_Wrapper::read_from (uint32_t addr, uint32_t amount)
|
||||||
|
{
|
||||||
|
eeprom_use (buffer, addr, amount, READ);
|
||||||
|
void *data = (void *)buffer;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
EEPROM_Wrapper::write_to (uint32_t addr, void *data, uint32_t size_of_data)
|
||||||
|
{
|
||||||
|
assert (size_of_data < EEPROM_MAX_BUFER_SIZE);
|
||||||
|
e_memcpy (data, buffer, size_of_data);
|
||||||
|
eeprom_use (buffer, addr, size_of_data, WRITE);
|
||||||
|
}
|
||||||
83
source/shoh/src/peripherals/EEPROMWrapper.h
Normal file
83
source/shoh/src/peripherals/EEPROMWrapper.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* EEPROMWrapper.h
|
||||||
|
*
|
||||||
|
* Created on: Dec 4, 2022
|
||||||
|
* Author: tylen
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EEPROMWRAPPER_H_
|
||||||
|
#define EEPROMWRAPPER_H_
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "chip.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*IAP_call) (uint32_t[], uint32_t[]);
|
||||||
|
|
||||||
|
typedef struct _eeprom
|
||||||
|
{
|
||||||
|
uint32_t data;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t mode;
|
||||||
|
uint32_t clock;
|
||||||
|
} EEPROM;
|
||||||
|
|
||||||
|
#define READ true
|
||||||
|
#define WRITE false
|
||||||
|
#define EEPROM_MAX_BUFER_SIZE 1000
|
||||||
|
|
||||||
|
class EEPROM_Wrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new eeprom wrapper object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
EEPROM_Wrapper ();
|
||||||
|
virtual ~EEPROM_Wrapper ();
|
||||||
|
/**
|
||||||
|
* @brief Read a string from EEPROM
|
||||||
|
*
|
||||||
|
* @param addr - address to read from
|
||||||
|
* @param amount - amount of bytes to read
|
||||||
|
* @return std::string - that was read
|
||||||
|
*/
|
||||||
|
std::string str_read_from (uint32_t addr, uint32_t amount);
|
||||||
|
/**
|
||||||
|
* @brief Write a string to EEPROM
|
||||||
|
*
|
||||||
|
* @param addr - address to write on
|
||||||
|
* @param str - string to write
|
||||||
|
*/
|
||||||
|
void write_to (uint32_t addr, std::string str);
|
||||||
|
/**
|
||||||
|
* @brief Read data from EEPROM
|
||||||
|
*
|
||||||
|
* @param addr - address to read from
|
||||||
|
* @param amount - amount of bytes to read
|
||||||
|
* @return void* - data that was read
|
||||||
|
*/
|
||||||
|
void *read_from (uint32_t addr, uint32_t amount);
|
||||||
|
/**
|
||||||
|
* @brief Write data to EEPROM
|
||||||
|
*
|
||||||
|
* @param addr - address to write on
|
||||||
|
* @param data - data to be written
|
||||||
|
* @param size_of_data - size of data to be written
|
||||||
|
*/
|
||||||
|
void write_to (uint32_t addr, void *data, uint32_t size_of_data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
IAP_call iap_exec;
|
||||||
|
uint32_t command[5], result[5];
|
||||||
|
EEPROM rom = { 0, 0, 0, 0, 72000 };
|
||||||
|
void eeprom_execute (EEPROM *rom);
|
||||||
|
void eeprom_use (uint8_t *data, uint32_t addr, uint32_t size, bool mode);
|
||||||
|
uint8_t buffer[EEPROM_MAX_BUFER_SIZE] = { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* EEPROMWRAPPER_H_ */
|
||||||
160
source/shoh/src/peripherals/I2C.cpp
Normal file
160
source/shoh/src/peripherals/I2C.cpp
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* I2C.cpp
|
||||||
|
*
|
||||||
|
* Created on: 21.2.2016
|
||||||
|
* Author: krl
|
||||||
|
* Based on example provided by NXP Semiconductors. See copyright notice
|
||||||
|
* below.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief I2CM bus master example using polling mode
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Copyright(C) NXP Semiconductors, 2014
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* @par
|
||||||
|
* Software that is described herein is for illustrative purposes only
|
||||||
|
* which provides customers with programming information regarding the
|
||||||
|
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||||
|
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||||
|
* all warranties, express or implied, including all implied warranties of
|
||||||
|
* merchantability, fitness for a particular purpose and non-infringement of
|
||||||
|
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||||
|
* or liability for the use of the software, conveys no license or rights under
|
||||||
|
* any patent, copyright, mask work right, or any other intellectual property
|
||||||
|
* rights in or to any products. NXP Semiconductors reserves the right to make
|
||||||
|
* changes in the software without notification. NXP Semiconductors also makes
|
||||||
|
* no representation or warranty that such application will be suitable for the
|
||||||
|
* specified use without further testing or modification.
|
||||||
|
*
|
||||||
|
* @par
|
||||||
|
* Permission to use, copy, modify, and distribute this software and its
|
||||||
|
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||||
|
* licensor's relevant copyrights in the software, without fee, provided that
|
||||||
|
* it is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||||
|
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||||
|
* this code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "I2C.h"
|
||||||
|
|
||||||
|
I2C::I2C (const I2C_config &cfg) : device (nullptr)
|
||||||
|
{
|
||||||
|
// if(cfg.device_number == 0) {
|
||||||
|
device = LPC_I2C0;
|
||||||
|
// board init must have been called before the pins can be configured
|
||||||
|
Chip_IOCON_PinMuxSet (LPC_IOCON, 0, 22, IOCON_DIGMODE_EN | cfg.i2c_mode);
|
||||||
|
Chip_IOCON_PinMuxSet (LPC_IOCON, 0, 23, IOCON_DIGMODE_EN | cfg.i2c_mode);
|
||||||
|
Chip_SWM_EnableFixedPin (SWM_FIXED_I2C0_SCL);
|
||||||
|
Chip_SWM_EnableFixedPin (SWM_FIXED_I2C0_SDA);
|
||||||
|
//}
|
||||||
|
// else {
|
||||||
|
// currently we support only I2C number 0
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (LPC_I2C0)
|
||||||
|
{
|
||||||
|
/* Enable I2C clock and reset I2C peripheral - the boot ROM does not
|
||||||
|
do this */
|
||||||
|
Chip_I2C_Init (LPC_I2C0);
|
||||||
|
|
||||||
|
/* Setup clock rate for I2C */
|
||||||
|
Chip_I2C_SetClockDiv (LPC_I2C0, cfg.clock_divider);
|
||||||
|
|
||||||
|
/* Setup I2CM transfer rate */
|
||||||
|
Chip_I2CM_SetBusSpeed (LPC_I2C0, cfg.speed);
|
||||||
|
|
||||||
|
/* Enable Master Mode */
|
||||||
|
Chip_I2CM_Enable (LPC_I2C0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
I2C::~I2C ()
|
||||||
|
{
|
||||||
|
// TODO Auto-generated destructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
I2C::write (uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize)
|
||||||
|
{
|
||||||
|
return transaction (devAddr, txBuffPtr, txSize, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
I2C::read (uint8_t devAddr, uint8_t *rxBuffPtr, uint16_t rxSize)
|
||||||
|
{
|
||||||
|
return transaction (devAddr, nullptr, 0, rxBuffPtr, rxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
I2C::transaction (uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize,
|
||||||
|
uint8_t *rxBuffPtr, uint16_t rxSize)
|
||||||
|
{
|
||||||
|
I2CM_XFER_T i2cmXferRec;
|
||||||
|
|
||||||
|
// make sure that master is idle
|
||||||
|
while (!Chip_I2CM_IsMasterPending (LPC_I2C0))
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Setup I2C transfer record */
|
||||||
|
i2cmXferRec.slaveAddr = devAddr;
|
||||||
|
i2cmXferRec.status = 0;
|
||||||
|
i2cmXferRec.txSz = txSize;
|
||||||
|
i2cmXferRec.rxSz = rxSize;
|
||||||
|
i2cmXferRec.txBuff = txBuffPtr;
|
||||||
|
i2cmXferRec.rxBuff = rxBuffPtr;
|
||||||
|
|
||||||
|
I2CM_XferBlocking (LPC_I2C0, &i2cmXferRec);
|
||||||
|
// Chip_I2CM_XferBlocking returns before stop condition is fully completed
|
||||||
|
// therefore we need to wait for master to be idle when doing back-to-back
|
||||||
|
// transactions (see beginning of the function)
|
||||||
|
|
||||||
|
/* Test for valid operation */
|
||||||
|
if (i2cmXferRec.status == I2CM_STATUS_OK)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transmit and Receive data in master mode */
|
||||||
|
/* This duplicates (and combines) the functionality of Chip_I2CM_Xfer and
|
||||||
|
* Chip_I2CM_XferBlocking with a modification that allows us to do a zero
|
||||||
|
* length write (needed to use honeywell humidity/temp sensor)
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
I2C::I2CM_XferBlocking (LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
/* start transfer */
|
||||||
|
|
||||||
|
/* set the transfer status as busy */
|
||||||
|
xfer->status = I2CM_STATUS_BUSY;
|
||||||
|
/* Clear controller state. */
|
||||||
|
Chip_I2CM_ClearStatus (pI2C, I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR);
|
||||||
|
/* Write Address and RW bit to data register */
|
||||||
|
// Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | (xfer->txSz == 0)); //
|
||||||
|
// original NXP version
|
||||||
|
// krl : both read and write lenght is 0 --> write (for honeywell temp
|
||||||
|
// sensor)
|
||||||
|
Chip_I2CM_WriteByte (pI2C, (xfer->slaveAddr << 1)
|
||||||
|
| (xfer->txSz == 0 && xfer->rxSz != 0));
|
||||||
|
/* Enter to Master Transmitter mode */
|
||||||
|
Chip_I2CM_SendStart (pI2C);
|
||||||
|
|
||||||
|
while (ret == 0)
|
||||||
|
{
|
||||||
|
/* wait for status change interrupt */
|
||||||
|
while (!Chip_I2CM_IsMasterPending (pI2C))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/* call state change handler */
|
||||||
|
ret = Chip_I2CM_XferHandler (pI2C, xfer);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
33
source/shoh/src/peripherals/I2C.h
Normal file
33
source/shoh/src/peripherals/I2C.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* I2C.h
|
||||||
|
*
|
||||||
|
* Created on: 21.2.2016
|
||||||
|
* Author: krl
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef I2C_H_
|
||||||
|
#define I2C_H_
|
||||||
|
|
||||||
|
#include "chip.h"
|
||||||
|
|
||||||
|
struct I2C_config {
|
||||||
|
unsigned int device_number;
|
||||||
|
unsigned int speed;
|
||||||
|
unsigned int clock_divider;
|
||||||
|
unsigned int i2c_mode;
|
||||||
|
I2C_config(unsigned int dn, unsigned int sp, unsigned int cd): device_number(dn), speed(sp), clock_divider(cd), i2c_mode(IOCON_SFI2C_EN) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class I2C {
|
||||||
|
public:
|
||||||
|
I2C(const I2C_config &cfg);
|
||||||
|
virtual ~I2C();
|
||||||
|
bool transaction(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize, uint8_t *rxBuffPtr, uint16_t rxSize);
|
||||||
|
bool write(uint8_t devAddr, uint8_t *txBuffPtr, uint16_t txSize);
|
||||||
|
bool read(uint8_t devAddr, uint8_t *rxBuffPtr, uint16_t rxSize);
|
||||||
|
private:
|
||||||
|
LPC_I2C_T *device;
|
||||||
|
static uint32_t I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* I2C_H_ */
|
||||||
289
source/shoh/src/peripherals/LiquidCrystal.cpp
Normal file
289
source/shoh/src/peripherals/LiquidCrystal.cpp
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
#include "LiquidCrystal.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include "chip.h"
|
||||||
|
|
||||||
|
#define LOW 0
|
||||||
|
#define HIGH 1
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void delayMicroseconds(unsigned int us)
|
||||||
|
{
|
||||||
|
// implement with RIT
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void delayMicroseconds(uint32_t delay)
|
||||||
|
{
|
||||||
|
static int init;
|
||||||
|
if(!init) {
|
||||||
|
// start core clock counter
|
||||||
|
CoreDebug->DEMCR |= 1 << 24;
|
||||||
|
DWT->CTRL |= 1;
|
||||||
|
init = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t start = DWT->CYCCNT;
|
||||||
|
delay = delay * 72; // assuming 72MHz clock
|
||||||
|
while(DWT->CYCCNT - start < delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// When the display powers up, it is configured as follows:
|
||||||
|
//
|
||||||
|
// 1. Display clear
|
||||||
|
// 2. Function set:
|
||||||
|
// DL = 1; 8-bit interface data
|
||||||
|
// N = 0; 1-line display
|
||||||
|
// F = 0; 5x8 dot character font
|
||||||
|
// 3. Display on/off control:
|
||||||
|
// D = 0; Display off
|
||||||
|
// C = 0; Cursor off
|
||||||
|
// B = 0; Blinking off
|
||||||
|
// 4. Entry mode set:
|
||||||
|
// I/D = 1; Increment by 1
|
||||||
|
// S = 0; No shift
|
||||||
|
//
|
||||||
|
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
|
||||||
|
// can't assume that its in that state when a sketch starts (and the
|
||||||
|
// LiquidCrystal constructor is called).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LiquidCrystal::LiquidCrystal(DigitalIoPin *rs, DigitalIoPin *enable,
|
||||||
|
DigitalIoPin *d0, DigitalIoPin *d1, DigitalIoPin *d2, DigitalIoPin *d3)
|
||||||
|
{
|
||||||
|
rs_pin = rs;
|
||||||
|
enable_pin = enable;
|
||||||
|
|
||||||
|
data_pins[0] = d0;
|
||||||
|
data_pins[1] = d1;
|
||||||
|
data_pins[2] = d2;
|
||||||
|
data_pins[3] = d3;
|
||||||
|
|
||||||
|
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||||
|
|
||||||
|
begin(16, 2); // default to 16x2 display
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||||
|
if (lines > 1) {
|
||||||
|
_displayfunction |= LCD_2LINE;
|
||||||
|
}
|
||||||
|
_numlines = lines;
|
||||||
|
_currline = 0;
|
||||||
|
|
||||||
|
// for some 1 line displays you can select a 10 pixel high font
|
||||||
|
if ((dotsize != 0) && (lines == 1)) {
|
||||||
|
_displayfunction |= LCD_5x10DOTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||||
|
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||||
|
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
||||||
|
delayMicroseconds(50000);
|
||||||
|
// Now we pull both RS and R/W low to begin commands
|
||||||
|
rs_pin->write(false); //digitalWrite(_rs_pin, LOW);
|
||||||
|
enable_pin->write(false); //digitalWrite(_enable_pin, LOW);
|
||||||
|
|
||||||
|
// note: this port supports only 4 bit mode
|
||||||
|
//put the LCD into 4 bit or 8 bit mode
|
||||||
|
if (! (_displayfunction & LCD_8BITMODE)) {
|
||||||
|
// this is according to the hitachi HD44780 datasheet
|
||||||
|
// figure 24, pg 46
|
||||||
|
|
||||||
|
// we start in 8bit mode, try to set 4 bit mode
|
||||||
|
write4bits(0x03);
|
||||||
|
delayMicroseconds(4500); // wait min 4.1ms
|
||||||
|
|
||||||
|
// second try
|
||||||
|
write4bits(0x03);
|
||||||
|
delayMicroseconds(4500); // wait min 4.1ms
|
||||||
|
|
||||||
|
// third go!
|
||||||
|
write4bits(0x03);
|
||||||
|
delayMicroseconds(150);
|
||||||
|
|
||||||
|
// finally, set to 4-bit interface
|
||||||
|
write4bits(0x02);
|
||||||
|
} else {
|
||||||
|
// this is according to the hitachi HD44780 datasheet
|
||||||
|
// page 45 figure 23
|
||||||
|
|
||||||
|
// Send function set command sequence
|
||||||
|
command(LCD_FUNCTIONSET | _displayfunction);
|
||||||
|
delayMicroseconds(4500); // wait more than 4.1ms
|
||||||
|
|
||||||
|
// second try
|
||||||
|
command(LCD_FUNCTIONSET | _displayfunction);
|
||||||
|
delayMicroseconds(150);
|
||||||
|
|
||||||
|
// third go
|
||||||
|
command(LCD_FUNCTIONSET | _displayfunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, set # lines, font size, etc.
|
||||||
|
command(LCD_FUNCTIONSET | _displayfunction);
|
||||||
|
|
||||||
|
// turn the display on with no cursor or blinking default
|
||||||
|
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||||
|
display();
|
||||||
|
|
||||||
|
// clear it off
|
||||||
|
clear();
|
||||||
|
|
||||||
|
// Initialize to default text direction (for romance languages)
|
||||||
|
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||||
|
// set the entry mode
|
||||||
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/********** high level commands, for the user! */
|
||||||
|
void LiquidCrystal::clear()
|
||||||
|
{
|
||||||
|
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||||
|
delayMicroseconds(2000); // this command takes a long time!
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiquidCrystal::home()
|
||||||
|
{
|
||||||
|
command(LCD_RETURNHOME); // set cursor position to zero
|
||||||
|
delayMicroseconds(2000); // this command takes a long time!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LiquidCrystal::print(std::string const &s)
|
||||||
|
{
|
||||||
|
print(s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiquidCrystal::print(const char *s)
|
||||||
|
{
|
||||||
|
while(*s) {
|
||||||
|
write(*s);
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
|
||||||
|
{
|
||||||
|
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
||||||
|
if ( row >= _numlines ) {
|
||||||
|
row = _numlines-1; // we count rows starting w/0
|
||||||
|
}
|
||||||
|
|
||||||
|
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn the display on/off (quickly)
|
||||||
|
void LiquidCrystal::noDisplay() {
|
||||||
|
_displaycontrol &= ~LCD_DISPLAYON;
|
||||||
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
|
}
|
||||||
|
void LiquidCrystal::display() {
|
||||||
|
_displaycontrol |= LCD_DISPLAYON;
|
||||||
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turns the underline cursor on/off
|
||||||
|
void LiquidCrystal::noCursor() {
|
||||||
|
_displaycontrol &= ~LCD_CURSORON;
|
||||||
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
|
}
|
||||||
|
void LiquidCrystal::cursor() {
|
||||||
|
_displaycontrol |= LCD_CURSORON;
|
||||||
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn on and off the blinking cursor
|
||||||
|
void LiquidCrystal::noBlink() {
|
||||||
|
_displaycontrol &= ~LCD_BLINKON;
|
||||||
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
|
}
|
||||||
|
void LiquidCrystal::blink() {
|
||||||
|
_displaycontrol |= LCD_BLINKON;
|
||||||
|
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These commands scroll the display without changing the RAM
|
||||||
|
void LiquidCrystal::scrollDisplayLeft(void) {
|
||||||
|
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||||
|
}
|
||||||
|
void LiquidCrystal::scrollDisplayRight(void) {
|
||||||
|
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is for text that flows Left to Right
|
||||||
|
void LiquidCrystal::leftToRight(void) {
|
||||||
|
_displaymode |= LCD_ENTRYLEFT;
|
||||||
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is for text that flows Right to Left
|
||||||
|
void LiquidCrystal::rightToLeft(void) {
|
||||||
|
_displaymode &= ~LCD_ENTRYLEFT;
|
||||||
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will 'right justify' text from the cursor
|
||||||
|
void LiquidCrystal::autoscroll(void) {
|
||||||
|
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||||
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will 'left justify' text from the cursor
|
||||||
|
void LiquidCrystal::noAutoscroll(void) {
|
||||||
|
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||||
|
command(LCD_ENTRYMODESET | _displaymode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows us to fill the first 8 CGRAM locations
|
||||||
|
// with custom characters
|
||||||
|
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
|
||||||
|
location &= 0x7; // we only have 8 locations 0-7
|
||||||
|
command(LCD_SETCGRAMADDR | (location << 3));
|
||||||
|
for (int i=0; i<8; i++) {
|
||||||
|
write(charmap[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********** mid level commands, for sending data/cmds */
|
||||||
|
|
||||||
|
inline void LiquidCrystal::command(uint8_t value) {
|
||||||
|
send(value, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t LiquidCrystal::write(uint8_t value) {
|
||||||
|
send(value, HIGH);
|
||||||
|
return 1; // assume sucess
|
||||||
|
}
|
||||||
|
|
||||||
|
/************ low level data pushing commands **********/
|
||||||
|
|
||||||
|
// write either command or data
|
||||||
|
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
|
||||||
|
rs_pin->write(mode); //digitalWrite(_rs_pin, mode);
|
||||||
|
|
||||||
|
write4bits(value>>4);
|
||||||
|
write4bits(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiquidCrystal::pulseEnable(void) {
|
||||||
|
enable_pin->write(false); //digitalWrite(_enable_pin, LOW);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
enable_pin->write(true); //digitalWrite(_enable_pin, HIGH);
|
||||||
|
delayMicroseconds(1); // enable pulse must be >450ns
|
||||||
|
enable_pin->write(false); //digitalWrite(_enable_pin, LOW);
|
||||||
|
delayMicroseconds(100); // commands need > 37us to settle
|
||||||
|
}
|
||||||
|
|
||||||
|
void LiquidCrystal::write4bits(uint8_t value) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
data_pins[i]->write((value >> i) & 0x01); //digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
pulseEnable();
|
||||||
|
}
|
||||||
|
|
||||||
97
source/shoh/src/peripherals/LiquidCrystal.h
Normal file
97
source/shoh/src/peripherals/LiquidCrystal.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#ifndef LiquidCrystal_h
|
||||||
|
#define LiquidCrystal_h
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include "chip.h"
|
||||||
|
#include "DigitalIoPin.h"
|
||||||
|
|
||||||
|
// commands
|
||||||
|
#define LCD_CLEARDISPLAY 0x01
|
||||||
|
#define LCD_RETURNHOME 0x02
|
||||||
|
#define LCD_ENTRYMODESET 0x04
|
||||||
|
#define LCD_DISPLAYCONTROL 0x08
|
||||||
|
#define LCD_CURSORSHIFT 0x10
|
||||||
|
#define LCD_FUNCTIONSET 0x20
|
||||||
|
#define LCD_SETCGRAMADDR 0x40
|
||||||
|
#define LCD_SETDDRAMADDR 0x80
|
||||||
|
|
||||||
|
// flags for display entry mode
|
||||||
|
#define LCD_ENTRYRIGHT 0x00
|
||||||
|
#define LCD_ENTRYLEFT 0x02
|
||||||
|
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||||
|
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||||
|
|
||||||
|
// flags for display on/off control
|
||||||
|
#define LCD_DISPLAYON 0x04
|
||||||
|
#define LCD_DISPLAYOFF 0x00
|
||||||
|
#define LCD_CURSORON 0x02
|
||||||
|
#define LCD_CURSOROFF 0x00
|
||||||
|
#define LCD_BLINKON 0x01
|
||||||
|
#define LCD_BLINKOFF 0x00
|
||||||
|
|
||||||
|
// flags for display/cursor shift
|
||||||
|
#define LCD_DISPLAYMOVE 0x08
|
||||||
|
#define LCD_CURSORMOVE 0x00
|
||||||
|
#define LCD_MOVERIGHT 0x04
|
||||||
|
#define LCD_MOVELEFT 0x00
|
||||||
|
|
||||||
|
// flags for function set
|
||||||
|
#define LCD_8BITMODE 0x10
|
||||||
|
#define LCD_4BITMODE 0x00
|
||||||
|
#define LCD_2LINE 0x08
|
||||||
|
#define LCD_1LINE 0x00
|
||||||
|
#define LCD_5x10DOTS 0x04
|
||||||
|
#define LCD_5x8DOTS 0x00
|
||||||
|
|
||||||
|
class LiquidCrystal {
|
||||||
|
public:
|
||||||
|
|
||||||
|
LiquidCrystal(DigitalIoPin *rs, DigitalIoPin *enable,
|
||||||
|
DigitalIoPin *d0, DigitalIoPin *d1, DigitalIoPin *d2, DigitalIoPin *d3);
|
||||||
|
|
||||||
|
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void home();
|
||||||
|
|
||||||
|
void noDisplay();
|
||||||
|
void display();
|
||||||
|
void noBlink();
|
||||||
|
void blink();
|
||||||
|
void noCursor();
|
||||||
|
void cursor();
|
||||||
|
void scrollDisplayLeft();
|
||||||
|
void scrollDisplayRight();
|
||||||
|
void leftToRight();
|
||||||
|
void rightToLeft();
|
||||||
|
void autoscroll();
|
||||||
|
void noAutoscroll();
|
||||||
|
|
||||||
|
void createChar(uint8_t, uint8_t[]);
|
||||||
|
void setCursor(uint8_t, uint8_t);
|
||||||
|
virtual size_t write(uint8_t);
|
||||||
|
void command(uint8_t);
|
||||||
|
void print(std::string const &s);
|
||||||
|
void print(const char *s);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void send(uint8_t, uint8_t);
|
||||||
|
void write4bits(uint8_t);
|
||||||
|
void pulseEnable();
|
||||||
|
|
||||||
|
DigitalIoPin *rs_pin; // LOW(false): command. HIGH(true): character.
|
||||||
|
DigitalIoPin *enable_pin; // activated by a HIGH pulse.
|
||||||
|
DigitalIoPin *data_pins[4];
|
||||||
|
|
||||||
|
uint8_t _displayfunction;
|
||||||
|
uint8_t _displaycontrol;
|
||||||
|
uint8_t _displaymode;
|
||||||
|
|
||||||
|
uint8_t _initialized;
|
||||||
|
|
||||||
|
uint8_t _numlines,_currline;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
315
source/shoh/src/peripherals/LpcUart.cpp
Normal file
315
source/shoh/src/peripherals/LpcUart.cpp
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
/*
|
||||||
|
* LpcUart.cpp
|
||||||
|
*
|
||||||
|
* Created on: 4.2.2019
|
||||||
|
* Author: keijo
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <mutex>
|
||||||
|
#include "LpcUart.h"
|
||||||
|
|
||||||
|
|
||||||
|
static LpcUart *u0;
|
||||||
|
static LpcUart *u1;
|
||||||
|
static LpcUart *u2;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
/**
|
||||||
|
* @brief UART interrupt handler using ring buffers
|
||||||
|
* @return Nothing
|
||||||
|
*/
|
||||||
|
void UART0_IRQHandler(void)
|
||||||
|
{
|
||||||
|
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
|
if(u0) {
|
||||||
|
u0->isr(&xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UART1_IRQHandler(void)
|
||||||
|
{
|
||||||
|
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
|
if(u1) {
|
||||||
|
u1->isr(&xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UART2_IRQHandler(void)
|
||||||
|
{
|
||||||
|
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
|
if(u2) {
|
||||||
|
u2->isr(&xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LpcUart::isr(portBASE_TYPE *hpw) {
|
||||||
|
// get interrupt status for notifications
|
||||||
|
uint32_t istat = Chip_UART_GetIntStatus(uart);
|
||||||
|
|
||||||
|
// chip library is used to handle receive and transmit
|
||||||
|
Chip_UART_IRQRBHandler(uart, &rxring, &txring);
|
||||||
|
|
||||||
|
// notify of the events handled
|
||||||
|
if(notify_rx && (istat & UART_STAT_RXRDY) ) vTaskNotifyGiveFromISR(notify_rx, hpw);
|
||||||
|
if(notify_tx && (istat & UART_STAT_TXRDY) ) vTaskNotifyGiveFromISR(notify_tx, hpw);
|
||||||
|
if(on_receive && (istat & UART_STAT_RXRDY) ) on_receive();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LpcUart::init = false;
|
||||||
|
|
||||||
|
LpcUart::LpcUart(const LpcUartConfig &cfg) {
|
||||||
|
CHIP_SWM_PIN_MOVABLE_T tx;
|
||||||
|
CHIP_SWM_PIN_MOVABLE_T rx;
|
||||||
|
CHIP_SWM_PIN_MOVABLE_T cts;
|
||||||
|
CHIP_SWM_PIN_MOVABLE_T rts;
|
||||||
|
bool use_rts = (cfg.rts.port >= 0);
|
||||||
|
bool use_cts = (cfg.cts.port >= 0);
|
||||||
|
|
||||||
|
if(!init) {
|
||||||
|
init = true;
|
||||||
|
/* Before setting up the UART, the global UART clock for USARTS 1-4
|
||||||
|
* must first be setup. This requires setting the UART divider and
|
||||||
|
* the UART base clock rate to 16x the maximum UART rate for all
|
||||||
|
* UARTs.
|
||||||
|
* */
|
||||||
|
/* Use main clock rate as base for UART baud rate divider */
|
||||||
|
Chip_Clock_SetUARTBaseClockRate(Chip_Clock_GetMainClockRate(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
uart = nullptr; // set default value before checking which UART to configure
|
||||||
|
|
||||||
|
if(cfg.pUART == LPC_USART0) {
|
||||||
|
if(u0) return; // already exists
|
||||||
|
else u0 = this;
|
||||||
|
tx = SWM_UART0_TXD_O;
|
||||||
|
rx = SWM_UART0_RXD_I;
|
||||||
|
rts = SWM_UART0_RTS_O;
|
||||||
|
cts = SWM_UART0_CTS_I;
|
||||||
|
irqn = UART0_IRQn;
|
||||||
|
}
|
||||||
|
else if(cfg.pUART == LPC_USART1) {
|
||||||
|
if(u1) return; // already exists
|
||||||
|
else u1 = this;
|
||||||
|
tx = SWM_UART1_TXD_O;
|
||||||
|
rx = SWM_UART1_RXD_I;
|
||||||
|
rts = SWM_UART1_RTS_O;
|
||||||
|
cts = SWM_UART1_CTS_I;
|
||||||
|
irqn = UART1_IRQn;
|
||||||
|
}
|
||||||
|
else if(cfg.pUART == LPC_USART2) {
|
||||||
|
if(u2) return; // already exists
|
||||||
|
else u2 = this;
|
||||||
|
tx = SWM_UART2_TXD_O;
|
||||||
|
rx = SWM_UART2_RXD_I;
|
||||||
|
use_rts = false; // UART2 does not support handshakes
|
||||||
|
use_cts = false;
|
||||||
|
irqn = UART2_IRQn;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart = cfg.pUART; // set the actual value after validity checking
|
||||||
|
|
||||||
|
|
||||||
|
if(cfg.tx.port >= 0) {
|
||||||
|
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.tx.port, cfg.tx.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||||
|
Chip_SWM_MovablePortPinAssign(tx, cfg.tx.port, cfg.tx.pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cfg.rx.port >= 0) {
|
||||||
|
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.rx.port, cfg.rx.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||||
|
Chip_SWM_MovablePortPinAssign(rx, cfg.rx.port, cfg.rx.pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(use_cts) {
|
||||||
|
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.cts.port, cfg.cts.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||||
|
Chip_SWM_MovablePortPinAssign(cts, cfg.cts.port, cfg.cts.pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(use_rts) {
|
||||||
|
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.rts.port, cfg.rts.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||||
|
Chip_SWM_MovablePortPinAssign(rts, cfg.rts.port, cfg.rts.pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
notify_rx = nullptr;
|
||||||
|
notify_tx = nullptr;
|
||||||
|
on_receive = nullptr;
|
||||||
|
/* Setup UART */
|
||||||
|
Chip_UART_Init(uart);
|
||||||
|
Chip_UART_ConfigData(uart, cfg.data);
|
||||||
|
Chip_UART_SetBaud(uart, cfg.speed);
|
||||||
|
|
||||||
|
if(use_rts && cfg.rs485) {
|
||||||
|
uart->CFG |= (1 << 20); // enable rs485 mode
|
||||||
|
//uart->CFG |= (1 << 18); // OE turnaraound time
|
||||||
|
uart->CFG |= (1 << 21);// driver enable polarity (active high)
|
||||||
|
}
|
||||||
|
|
||||||
|
Chip_UART_Enable(uart);
|
||||||
|
Chip_UART_TXEnable(uart);
|
||||||
|
|
||||||
|
/* Before using the ring buffers, initialize them using the ring
|
||||||
|
buffer init function */
|
||||||
|
RingBuffer_Init(&rxring, rxbuff, 1, UART_RB_SIZE);
|
||||||
|
RingBuffer_Init(&txring, txbuff, 1, UART_RB_SIZE);
|
||||||
|
|
||||||
|
|
||||||
|
/* Enable receive data and line status interrupt */
|
||||||
|
Chip_UART_IntEnable(uart, UART_INTEN_RXRDY);
|
||||||
|
Chip_UART_IntDisable(uart, UART_INTEN_TXRDY); /* May not be needed */
|
||||||
|
|
||||||
|
NVIC_SetPriority(irqn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
|
||||||
|
/* Enable UART interrupt */
|
||||||
|
NVIC_EnableIRQ(irqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
LpcUart::~LpcUart() {
|
||||||
|
if(uart != nullptr) {
|
||||||
|
NVIC_DisableIRQ(irqn);
|
||||||
|
Chip_UART_IntDisable(uart, UART_INTEN_RXRDY);
|
||||||
|
Chip_UART_IntDisable(uart, UART_INTEN_TXRDY);
|
||||||
|
|
||||||
|
if(uart == LPC_USART0) {
|
||||||
|
u0 = nullptr;
|
||||||
|
}
|
||||||
|
else if(uart == LPC_USART1) {
|
||||||
|
u1 = nullptr;
|
||||||
|
}
|
||||||
|
else if(uart == LPC_USART2) {
|
||||||
|
u2 = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LpcUart::set_on_receive(void(*cb)(void))
|
||||||
|
{
|
||||||
|
on_receive = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int LpcUart::free()
|
||||||
|
{
|
||||||
|
std::lock_guard<Fmutex> lock(write_mutex);
|
||||||
|
|
||||||
|
return UART_RB_SIZE - RingBuffer_GetCount(&txring);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LpcUart::peek()
|
||||||
|
{
|
||||||
|
std::lock_guard<Fmutex> lock(read_mutex);
|
||||||
|
|
||||||
|
return RingBuffer_GetCount(&rxring);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LpcUart::read(char &c)
|
||||||
|
{
|
||||||
|
return read(&c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LpcUart::read(char *buffer, int len)
|
||||||
|
{
|
||||||
|
std::lock_guard<Fmutex> lock(read_mutex);
|
||||||
|
|
||||||
|
if(RingBuffer_GetCount(&rxring) <= 0) {
|
||||||
|
notify_rx = xTaskGetCurrentTaskHandle();
|
||||||
|
while(RingBuffer_GetCount(&rxring) <= 0) {
|
||||||
|
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||||
|
}
|
||||||
|
notify_rx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Chip_UART_ReadRB(uart, &rxring, buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int LpcUart::read(char *buffer, int len, TickType_t total_timeout, TickType_t ic_timeout)
|
||||||
|
{
|
||||||
|
std::lock_guard<Fmutex> lock(read_mutex);
|
||||||
|
|
||||||
|
// we can't read more than ring buffer size at a time
|
||||||
|
if(len > UART_RB_SIZE) len = UART_RB_SIZE;
|
||||||
|
|
||||||
|
TimeOut_t timeoutState;
|
||||||
|
vTaskSetTimeOutState(&timeoutState);
|
||||||
|
|
||||||
|
notify_rx = xTaskGetCurrentTaskHandle();
|
||||||
|
while(RingBuffer_GetCount(&rxring) < len && xTaskCheckForTimeOut(&timeoutState, &total_timeout) == pdFALSE) {
|
||||||
|
TickType_t timeout = total_timeout > ic_timeout ? ic_timeout : total_timeout;
|
||||||
|
if(ulTaskNotifyTake( pdTRUE, timeout ) == 0) break;
|
||||||
|
}
|
||||||
|
notify_rx = nullptr;
|
||||||
|
|
||||||
|
return Chip_UART_ReadRB(uart, &rxring, buffer, len);;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LpcUart::write(char c)
|
||||||
|
{
|
||||||
|
return write(&c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LpcUart::write(const char *s)
|
||||||
|
{
|
||||||
|
return write(s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
int LpcUart::write(const char *buffer, int len)
|
||||||
|
{
|
||||||
|
std::lock_guard<Fmutex> lock(write_mutex);
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
notify_tx = xTaskGetCurrentTaskHandle();
|
||||||
|
|
||||||
|
while(len > pos) {
|
||||||
|
// restrict single write to ring buffer size
|
||||||
|
int size = (len - pos) > UART_RB_SIZE ? UART_RB_SIZE : (len - pos);
|
||||||
|
|
||||||
|
// wait until we have space in the ring buffer
|
||||||
|
while(UART_RB_SIZE - RingBuffer_GetCount(&txring) < size) {
|
||||||
|
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||||
|
}
|
||||||
|
pos += Chip_UART_SendRB(uart, &txring, buffer+pos, size);
|
||||||
|
}
|
||||||
|
notify_tx = nullptr;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LpcUart::txbreak(bool brk)
|
||||||
|
{
|
||||||
|
// break handling not implemented yet
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LpcUart::rxbreak()
|
||||||
|
{
|
||||||
|
// break handling not implemented yet
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LpcUart::speed(int bps)
|
||||||
|
{
|
||||||
|
std::lock_guard<Fmutex> lockw(write_mutex);
|
||||||
|
std::lock_guard<Fmutex> lockr(read_mutex);
|
||||||
|
|
||||||
|
Chip_UART_SetBaud(uart, bps);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LpcUart::txempty()
|
||||||
|
{
|
||||||
|
std::lock_guard<Fmutex> lock(write_mutex);
|
||||||
|
|
||||||
|
return (RingBuffer_GetCount(&txring) == 0);
|
||||||
|
}
|
||||||
72
source/shoh/src/peripherals/LpcUart.h
Normal file
72
source/shoh/src/peripherals/LpcUart.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* LpcUart.h
|
||||||
|
*
|
||||||
|
* Created on: 4.2.2019
|
||||||
|
* Author: keijo
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LPCUART_H_
|
||||||
|
#define LPCUART_H_
|
||||||
|
|
||||||
|
#include "chip.h"
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
#include "Fmutex.h"
|
||||||
|
|
||||||
|
struct LpcPinMap {
|
||||||
|
int port; /* set to -1 to indicate unused pin */
|
||||||
|
int pin; /* set to -1 to indicate unused pin */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LpcUartConfig {
|
||||||
|
LPC_USART_T *pUART;
|
||||||
|
uint32_t speed;
|
||||||
|
uint32_t data;
|
||||||
|
bool rs485;
|
||||||
|
LpcPinMap tx;
|
||||||
|
LpcPinMap rx;
|
||||||
|
LpcPinMap rts; /* used as output enable if RS-485 mode is enabled */
|
||||||
|
LpcPinMap cts;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LpcUart {
|
||||||
|
public:
|
||||||
|
LpcUart(const LpcUartConfig &cfg);
|
||||||
|
LpcUart(const LpcUart &) = delete;
|
||||||
|
virtual ~LpcUart();
|
||||||
|
int free(); /* get amount of free space in transmit buffer */
|
||||||
|
int peek(); /* get number of received characters in receive buffer */
|
||||||
|
int write(char c);
|
||||||
|
int write(const char *s);
|
||||||
|
int write(const char *buffer, int len);
|
||||||
|
int read(char &c); /* get a single character. Returns number of characters read --> returns 0 if no character is available */
|
||||||
|
int read(char *buffer, int len);
|
||||||
|
int read(char *buffer, int len, TickType_t total_timeout, TickType_t ic_timeout = portMAX_DELAY);
|
||||||
|
void txbreak(bool brk); /* set break signal on */
|
||||||
|
bool rxbreak(); /* check if break is received */
|
||||||
|
void speed(int bps); /* change transmission speed */
|
||||||
|
bool txempty();
|
||||||
|
void set_on_receive(void(*cb)(void));
|
||||||
|
|
||||||
|
void isr(portBASE_TYPE *hpw); /* ISR handler. This will be called by the HW ISR handler. Do not call from application */
|
||||||
|
private:
|
||||||
|
LPC_USART_T *uart;
|
||||||
|
IRQn_Type irqn;
|
||||||
|
/* currently we support only fixed size ring buffers */
|
||||||
|
static const int UART_RB_SIZE = 128;
|
||||||
|
/* Transmit and receive ring buffers */
|
||||||
|
RINGBUFF_T txring;
|
||||||
|
RINGBUFF_T rxring;
|
||||||
|
uint8_t rxbuff[UART_RB_SIZE];
|
||||||
|
uint8_t txbuff[UART_RB_SIZE];
|
||||||
|
static bool init; /* set when first UART is initialized. We have a global clock setting for all UARTSs */
|
||||||
|
TaskHandle_t notify_rx;
|
||||||
|
TaskHandle_t notify_tx;
|
||||||
|
void (*on_receive)(void); // callback for received data notifications
|
||||||
|
Fmutex read_mutex;
|
||||||
|
Fmutex write_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* LPCUART_H_ */
|
||||||
Loading…
x
Reference in New Issue
Block a user