This commit is contained in:
pvvx 2017-06-21 03:00:20 +03:00
parent 34d3652711
commit 39f77eb92b
1844 changed files with 899433 additions and 7 deletions

View file

@ -0,0 +1,23 @@
/*
* Simple ADC DRV (adc_drv.h)
*
* Created on: 19 июн. 2017 г.
* Author: pvvx
*/
#ifndef _DRIVER_ADC_DRV_H_
#define _DRIVER_ADC_DRV_H_
#include "rtl8195a.h"
#include "rtl8195a_adc.h"
void ADCIrqInit(IRQ_FUN IrqFunc, u32 IrqData, u32 intr_enable); // intr_enable = bits: REG_ADC_INTR_EN - BIT_ADC_FIFO_RD_ERROR_EN | BIT_ADC_FIFO_RD_REQ_EN | BIT_ADC_FIFO_FULL_EN ...
void ADCIrqDeInit(void);
void ADCInit(ADC_MODULE_SEL adc_idx); // RTL8711AM: adc_idx = ADC2_SEL = 2
void ADCDeInit(void);
void ADCEnable(void); // ADC Start
void ADCDisable(void); // ADC Stop
#endif /* _DRIVER_ADC_DRV_H_ */

View file

@ -11,7 +11,8 @@
#define WEB_DEBUG_FUNCTIONS 1 // =1 - включить в WEB отладочные функции, =0 отключить (остается только конфигурация WiFi)
// #define WEB_INA219_DRV 1 (set in project.mk)
// #define WEB_INA219_DRV 1 (set in project.mk !)
// #define WEB_ADC_DRV 1 (set in project.mk !)
#endif // _user_config_h_

211
project/src/adc_ws/adc_ws.c Normal file
View file

@ -0,0 +1,211 @@
/*
* ADC + Websocket
*
* Created on: 18 июн. 2017 г.
* Author: pvvx
*/
#include <platform_opts.h>
#include "rtl8195a.h"
#include "device.h"
#include "PinNames.h"
#include "basic_types.h"
#include "diag.h"
#include "osdep_api.h"
#include "FreeRTOS.h"
#include "diag.h"
//------------------------------------------------------------------------------
#include "objects.h"
#include "PinNames.h"
#include "hal_adc.h"
#include "analogin_api.h"
#include "timer_api.h"
//#include "strproc.h"
#include "web_srv.h"
#include "websock.h"
#include "driver/adc_drv.h"
#include "rtl8195a/rtl_libc.h"
//------------------------------------------------------------------------------
#define ADC_USE_TIMER TIMER3 // если назначено, то для чтения ADC используется таймер
// иначе ADC int
//------------------------------------------------------------------------------
#ifndef CONFIG_MBED_ENABLED
#define malloc pvPortMalloc
#define zalloc pvPortZalloc
#define free vPortFree
#endif
//------------------------------------------------------------------------------
typedef union _adc_data {
unsigned short us;
} ADC_DATA, *PADC_DATA;
typedef struct _adc_drv {
signed char init; // флаг
unsigned char tmp;
unsigned short count; // счетчик считанных значений
unsigned short overrun; // счет переполнений буфера
unsigned short buf_idx; // объем буфера pbuf[buf_idx+1], максимальный индекс-номер замера
unsigned short buf_rx; // индекс-номер ещё не считанного замера
unsigned short buf_tx; // индекс-номер для записи следующего замера
PADC_DATA pbuf;
#ifdef ADC_USE_TIMER
gtimer_t timer;
#endif
} ADC_DRV, *PADC_DRV;
#define mMIN(a, b) ((a<b)?a:b)
#define mMAX(a, b) ((a>b)?a:b)
ADC_DRV adc_drv = {
.buf_idx = (1460*2 - 80)/(sizeof(ADC_DATA)/2) // циклический буфер на ~1420 замеров (см. sizeof(ADC_DATA))
// Если шаг заполнения 1 ms -> буфер на 1.4 сек
// Оптимизация под TCP: (TCP_MSS*2 - 80)/2 = (1460*2 - 80)/2 = 1420
};
void adc_int_handler(void *par) {
PADC_DRV p = par; // &adc_drv
if(p->pbuf) {
#ifndef ADC_USE_TIMER
int i = 4;
while(i--)
#endif
{
PADC_DATA pd = p->pbuf + p->buf_tx;
pd->us = HAL_ADC_READ32(REG_ADC_FIFO_READ); // 2 -> sample -> 24.4 kHz (if ADC irq!)
// (void)HAL_ADC_READ32(REG_ADC_FIFO_READ); // 4 sample -> 12.2 kHz (if ADC irq!)
// (void)HAL_ADC_READ32(REG_ADC_FIFO_READ); // 6 sample -> 8.133 kHz (if ADC irq!)
// (void)HAL_ADC_READ32(REG_ADC_FIFO_READ); // 8 sample -> 6.1 kHz (if ADC irq!)
if(p->buf_tx >= p->buf_idx) p->buf_tx = 0;
else p->buf_tx++;
if(p->buf_rx == p->buf_tx) {
p->overrun++; // todo: if(p->overrun++ > 100000) deinit() ?
if(p->buf_rx >= p->buf_idx) p->buf_rx = 0;
else p->buf_rx++;
};
}
/* Clear ADC Status */
(void)HAL_ADC_READ32(REG_ADC_INTR_STS);
};
}
size_t adc_getdata(void *pd, uint16 cnt)
{
PADC_DRV p = &adc_drv;
if(p->init <= 0) return 0;
unsigned short *pus = (unsigned short *) pd;
taskDISABLE_INTERRUPTS();
uint16 buf_rx = p->buf_rx;
*pus++ = cnt; // кол-во замеров
*pus++ = p->count + p->overrun; // индекс замера для анализа пропусков на стороне приемника
// если не пропущено, то равен прошлому + кол-во считанных замеров в прошлом блоке
p->count += cnt; // p->overrun = 0;
unsigned char *puc = (unsigned char *) pus;
if(cnt) {
uint16 lend = buf_rx + cnt;
if(lend > p->buf_idx) {
lend -= p->buf_idx + 1;
p->buf_rx = lend;
} else {
p->buf_rx = lend;
lend = 0;
};
size_t len = (cnt - lend) *sizeof(ADC_DATA);
if(len) memcpy(puc, (void *)(p->pbuf + buf_rx), len);
if(lend) memcpy(puc + len, (void *)p->pbuf, lend *sizeof(ADC_DATA));
}
taskENABLE_INTERRUPTS();
return cnt * sizeof(ADC_DATA) + 4;
}
uint16 adc_chkdata(uint16 cnt)
{
PADC_DRV p = &adc_drv;
if(p->init <= 0) return 0;
int len = p->buf_tx - p->buf_rx;
if(len < 0) len += p->buf_idx + 1;
if(cnt > (uint16)len) cnt = (uint16)len;
return cnt;
}
int adc_ws(TCP_SERV_CONN *ts_conn, char cmd)
{
PADC_DRV p = &adc_drv;
switch(cmd) {
case 'd': // deinit
if(p->init > 0) {
#ifdef ADC_USE_TIMER
gtimer_stop(&p->timer);
gtimer_deinit(&p->timer);
ADCDisable();
#else
ADCDisable();
ADCIrqDeInit();
#endif
ADCDeInit();
if(p->pbuf) {
free(p->pbuf);
p->pbuf = NULL;
}
p->init = -1;
return 0;
}
return 1;
case 'c': // get count
return adc_chkdata(p->buf_idx + 1);
case 'i': // init
return p->init;
default: // get_data
if(p->init <= 0) {
p->count = 0;
p->overrun = 0;
// p->errs = 0;
if(!p->pbuf) {
p->pbuf = zalloc((p->buf_idx + 1) * sizeof(ADC_DATA));
if(!p->pbuf) {
error_printf("Error create buffer!\n");
return -1;
};
p->buf_tx = 0;
p->buf_rx = 0;
};
ADCInit(ADC2_SEL);
#ifdef ADC_USE_TIMER
// Initial a periodical timer
gtimer_init(&p->timer, ADC_USE_TIMER);
gtimer_start_periodical(&p->timer, 1000, (void*)adc_int_handler, (uint32_t)p);
rtl_printf("ADC Timer Period = %u us\n", &p->timer.hal_gtimer_adp.TimerLoadValueUs);
#else
ADCIrqInit(adc_int_handler,(uint32)p, BIT_ADC_FIFO_FULL_EN); // BIT_ADC_FIFO_RD_REQ_EN ?
#endif
ADCEnable();
p->init = 1;
// return 0;
}
case 'g': // get
{
uint32 i = adc_chkdata(p->buf_idx + 1);
if(i) {
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *)ts_conn->linkd;
i = mMIN((web_conn->msgbufsize / sizeof(ADC_DATA)), i);
if(websock_tx_frame(ts_conn, WS_OPCODE_BINARY | WS_FRAGMENT_FIN, web_conn->msgbuf, adc_getdata(web_conn->msgbuf, i)) != ERR_OK)
return -1;
}
return i;
}
}
return -1;
}

View file

@ -0,0 +1,198 @@
/*
* Simple ADC DRV (adc_drv.c)
* Created on: 18 июн. 2017 г.
* Author: pvvx
*/
#include <platform_opts.h>
#include "platform_autoconf.h"
#include "diag.h"
#include "rtl8195a_adc.h"
#include "hal_adc.h"
#include "driver/adc_drv.h"
//------------------------------------------------------------------------------
void ADCIrqInit(IRQ_FUN IrqFunc, u32 IrqData, u32 intr_enable) {
IRQ_HANDLE IrqHandle = {
.IrqNum = ADC_IRQ,
.Priority = 5
};
IrqHandle.Data = IrqData;
IrqHandle.IrqFun = IrqFunc;
InterruptRegister(&IrqHandle);
InterruptEn(&IrqHandle);
HAL_ADC_WRITE32(REG_ADC_INTR_EN, intr_enable);
}
void ADCIrqDeInit(void) {
IRQ_HANDLE IrqHandle = {
.IrqNum = ADC_IRQ,
.Priority = 5,
.Data = (u32)NULL,
.IrqFun = (IRQ_FUN) NULL
};
HAL_ADC_WRITE32(REG_ADC_INTR_EN, 0);
InterruptUnRegister(&IrqHandle);
}
void ADCEnable(void) {
/* Clear ADC Status */
(void)HAL_ADC_READ32(REG_ADC_INTR_STS);
u32 AdcTempDat = HAL_ADC_READ32(REG_ADC_POWER);
AdcTempDat &= (~BIT_ADC_PWR_AUTO);
AdcTempDat |= 0x02;
HAL_ADC_WRITE32(REG_ADC_POWER, AdcTempDat);
AdcTempDat |= 0x04;
HAL_ADC_WRITE32(REG_ADC_POWER, AdcTempDat);
AdcTempDat &= (~0x08);
HAL_ADC_WRITE32(REG_ADC_POWER, AdcTempDat);
/* */
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD0,
HAL_ADC_READ32(REG_ADC_ANAPAR_AD0) | BIT_ADC_EN_MANUAL);
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD1,
HAL_ADC_READ32(REG_ADC_ANAPAR_AD1) | BIT_ADC_EN_MANUAL);
}
void ADCDisable(void) {
#if ADC_USE_IRQ
HAL_ADC_WRITE32(REG_ADC_INTR_EN, 0);
#endif
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD0,
HAL_ADC_READ32(REG_ADC_ANAPAR_AD0) & (~BIT_ADC_EN_MANUAL));
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD1,
HAL_ADC_READ32(REG_ADC_ANAPAR_AD1) & (~BIT_ADC_EN_MANUAL));
HAL_ADC_WRITE32(REG_ADC_POWER,
HAL_ADC_READ32(REG_ADC_POWER)
& (~(BIT_ADC_PWR_AUTO)));
}
#ifdef CONFIG_SOC_PS_MODULE
static void ADCEnablePS(void)
{
REG_POWER_STATE adcPwrState;
// To register a new peripheral device power state
adcPwrState.FuncIdx = ADC0;
adcPwrState.PwrState = ACT;
RegPowerState(adcPwrState);
}
#endif
void ADCInit(ADC_MODULE_SEL adc_idx) {
/* ADC Function and Clock Enable */
/* To release DAC delta sigma clock gating */
HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_SYSPLL_CTRL2,
HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_SYSPLL_CTRL2) | BIT25);
/* Turn on DAC active clock */
ACTCK_ADC_CCTRL(ON);
/* Enable DAC0 module */
ADC0_FCTRL(ON);
/* Enable ADC power cut ? */
// ADCEnablePW();
/* ADC Control register set-up*/
HAL_ADC_WRITE32(REG_ADC_CONTROL,
BIT_CTRL_ADC_COMP_ONLY(ADC_FEATURE_DISABLED) // compare mode only enable (without FIFO enable)
| BIT_CTRL_ADC_ONESHOT(ADC_FEATURE_DISABLED) // one-shot mode enable
| BIT_CTRL_ADC_OVERWRITE(ADC_FEATURE_DISABLED) // overwrite mode enable
| BIT_CTRL_ADC_ENDIAN(ADC_DATA_ENDIAN_LITTLE) // endian selection
| BIT_CTRL_ADC_BURST_SIZE(8) // DMA operation threshold
| BIT_CTRL_ADC_THRESHOLD(8) // one shot mode threshold
| BIT_CTRL_ADC_DBG_SEL(ADC_DBG_SEL_DISABLE));
#if 0
/* ADC compare value and compare method setting*/
switch (adc_idx) {
case ADC0_SEL:
HAL_ADC_WRITE32(REG_ADC_COMP_VALUE_L,
(HAL_ADC_READ32(REG_ADC_COMP_VALUE_L)
& (~(BIT_ADC_COMP_TH_0(0xFFFF))))
| BIT_CTRL_ADC_COMP_TH_0(0) // ADC compare mode threshold
);
break;
case ADC1_SEL:
HAL_ADC_WRITE32(REG_ADC_COMP_VALUE_L,
(HAL_ADC_READ32(REG_ADC_COMP_VALUE_L)
& (~(BIT_ADC_COMP_TH_1(0xFFFF))))
| BIT_CTRL_ADC_COMP_TH_1(0) // ADC compare mode threshold
);
break;
case ADC2_SEL:
HAL_ADC_WRITE32(REG_ADC_COMP_VALUE_H,
(HAL_ADC_READ32(REG_ADC_COMP_VALUE_H)
& (~(BIT_ADC_COMP_TH_2(0xFFFF))))
| BIT_CTRL_ADC_COMP_TH_2(0) // ADC compare mode threshold
);
break;
case ADC3_SEL:
HAL_ADC_WRITE32(REG_ADC_COMP_VALUE_H,
(HAL_ADC_READ32(REG_ADC_COMP_VALUE_H)
& (~(BIT_ADC_COMP_TH_3(0xFFFF))))
| BIT_CTRL_ADC_COMP_TH_3(0) // ADC compare mode threshold
);
break;
}
/* ADC compare mode setting */
HAL_ADC_WRITE32(REG_ADC_COMP_SET,
HAL_ADC_READ32(REG_ADC_COMP_SET)
& (~(1 << adc_idx))); // compare mode control : less than the compare threshold
#endif
/* ADC audio mode set-up */
/* ADC enable manually setting */
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD0,
HAL_ADC_READ32(REG_ADC_ANAPAR_AD0)
// & (~(BIT_ADC_AUDIO_EN)))
// & (~(BIT_ADC_EN_MANUAL))
| BIT_ADC_AUDIO_EN // ADC audio mode enable
| BIT_ADC_EN_MANUAL // ADC enable manually
);
/* ADC analog parameter 0 */
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD0,
(HAL_ADC_READ32(REG_ADC_ANAPAR_AD0)
// & (~BIT14) //ADC Input is internal?
| (BIT14))
& (~(BIT3|BIT2)));
/* ADC analog parameter 1 */
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD1,
(HAL_ADC_READ32(REG_ADC_ANAPAR_AD1) & (~BIT1)) | (BIT2|BIT0));
/* ADC analog parameter 2 */
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD2, 0x67884400);
/* ADC analog parameter 3 */
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD3, 0x77780039);
/* ADC analog parameter 4 */
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD4, 0x0004d501);
/* ADC analog parameter 5 */
HAL_ADC_WRITE32(REG_ADC_ANAPAR_AD5, 0x1E010800);
#ifdef CONFIG_SOC_PS_MODULE
ADCEnablePS();
#endif
}
void ADCDeInit(void) {
#ifdef CONFIG_SOC_PS_MODULE
REG_POWER_STATE adcPwrState;
u8 HwState;
adcPwrState.FuncIdx = ADC0;
QueryRegPwrState(adcPwrState.FuncIdx, &(adcPwrState.PwrState), &HwState);
// if the power state isn't ACT, then switch the power state back to ACT first
if ((adcPwrState.PwrState != ACT) && (adcPwrState.PwrState != INACT)) {
ADCEnablePS();
QueryRegPwrState(adcPwrState.FuncIdx, &(adcPwrState.PwrState), &HwState);
}
if (adcPwrState.PwrState == ACT) {
adcPwrState.PwrState = INACT;
RegPowerState(adcPwrState);
}
#endif
/* Turn on DAC active clock */
ACTCK_ADC_CCTRL(OFF);
/* Enable DAC1 module */
ADC0_FCTRL(OFF);
/* To release DAC delta sigma clock gating */
HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_SYSPLL_CTRL2,
HAL_READ32(SYSTEM_CTRL_BASE, REG_SYS_SYSPLL_CTRL2) & (~(BIT25)));
}

View file

@ -450,6 +450,16 @@ extern int ina219_ws(TCP_SERV_CONN *ts_conn, char cmd);
else tcp_puts("%d", x);
}
}
#endif
#ifdef WEB_ADC_DRV
else ifcmp("adc") {
if(CheckSCB(SCB_WEBSOC)) {
extern int adc_ws(TCP_SERV_CONN *ts_conn, char cmd);
int x = adc_ws(ts_conn, cstr[6]);
if(x < 0) SetSCB(SCB_FCLOSE|SCB_DISCONNECT);
else tcp_puts("%d", x);
}
}
#endif
else ifcmp("cfg_") {
cstr += 4;