/* ------------------------------------------------------------------------------------------------ */
/* FILE :		Demo_6_STM3220G_ATOLLIC.c															*/
/*																									*/
/* CONTENTS :																						*/
/*				Demo for the ST microelectronics STM3220G evaluation board							*/
/*				The ADC converts the value set by the trimmer										*/
/*				The value read is displayed on the serial port and LCD								*/
/*				Serial port settings:																*/
/*							Baud Rate: 115200														*/
/*							Data bits:      8														*/
/*							Stop bits:		1														*/
/*							Parity:      none														*/
/*							Flow Ctrl:   none														*/
/*																									*/
/*																									*/
/* Copyright (c) 2012-2014, Code-Time Technologies Inc. All rights reserved.						*/
/*																									*/
/* Code-Time Technologies retains all right, title, and interest in and to this work				*/
/*																									*/
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS							*/
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF										*/
/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL							*/
/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR								*/
/* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,							*/
/* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR							*/
/* OTHER DEALINGS IN THE SOFTWARE.																	*/
/*																									*/
/*																									*/
/*	$Revision: 1.3 $																				*/
/*	$Date: 2012/06/17 18:41:36 $																	*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

#if OS_DEMO != 6
	#error "Wrong OS_DEMO value" 
#endif

#include <stdio.h>
#include <stdarg.h>
#include <Abassi.h>

/* ------------------------------------------------ */

#include "stm32f2xx.h"
#include "stm32_eval.h"
#include "stm322xg_eval_lcd.h"
#include "stm322xg_eval_ioe.h"

#define BAUDRATE	   115200						/* Serial port baud rate						*/
#define SYS_FREQ	120000000						/* Processor clock frequency					*/

#if 0											/* Setting != 0, looks like old plasma display	*/
  #define BG_COLOR	LCD_COLOR_BLACK
  #define FG_COLOR	(((0xFC>>3)<<11)|((0x39>>2)<<5)|(0x02>>3))
#else
  #define BG_COLOR	(((0xFC>>3)<<11)|((0x39>>2)<<5)|(0x02>>3))
  #define FG_COLOR	LCD_COLOR_BLACK
#endif

#define ADC3_DR_ADDRESS	((uint32_t)0x4001224C)

void ADC3_CH7_DMA_Config(void);
__IO unsigned short ADC3ConvertedValue = 0;

USART_InitTypeDef USART_InitStructure;

/* ------------------------------------------------ */

MBX_t *MbxADC;										/* Mailbox the ISR put thre ADC value in		*/
MBX_t *MbxTime;										/* Mailbox the ISR put the RTC valeu in			*/

TSK_t *A_E;

/* ------------------------------------------------ */

void ADChandler(void);

/* ------------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------------ */

int main()
{
unsigned int ADCval;								/* ADC value received from the mailbox			*/
int          ii;									/* General purpose								*/
int          jj;									/* General purpose								*/
intptr_t     Msg;									/* Message received from a mailbox				*/
int          Prio = 0;								/* SysTick interrupt priority					*/
unsigned int Time;									/* Running time value, received from ISR		*/
int          Tdigits[4];							/* To print the RTC								*/
int         *TimerBase;								/* SysTick register base address				*/

static char  Str[64];								/* String to print the update on serial port	*/

/* ------------------------------------------------ */
/* 	Processor clock set-up							*/

	SystemInit();

/* ------------------------------------------------ */
/* 	RTOS set-up										*/

	OSstart();

	A_E = TSKmyID();

/* ------------------------------------------------ */
/* UART set-up										*/

	USART_InitStructure.USART_BaudRate            = BAUDRATE;
	USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits            = USART_StopBits_1;
	USART_InitStructure.USART_Parity              = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;

	STM_EVAL_COMInit(COM1, &USART_InitStructure);

	setvbuf(stdin,  NULL, _IONBF, 0);
	setvbuf(stdout, NULL, _IONBF, 0);

/* ------------------------------------------------ */
/* LCD set-up										*/

	STM322xG_LCD_Init();

	LCD_Clear(LCD_COLOR_BLACK);

	LCD_SetColors(FG_COLOR, BG_COLOR);

/* ------------------------------------------------ */
/* SysTick Set-up									*/

	TimerBase = (int *)0xE000E000;
	((volatile int *)0xE000Ed20)[0] = (((volatile int *)0xE000Ed20)[0] & 0x1FFFFFFF)
	                                |   ((Prio & 7) << 29);
	OSisrInstall(-1, TIMtick);						/* Install the OS timer tick function			*/
	TimerBase[5] = ((((SYS_FREQ)/100000) * OS_TIMER_US)/10)-1;
	TimerBase[4] = 0x7;								/* internal clock / int & enable				*/

/* ------------------------------------------------ */
/* ADC & DMA set-up									*/

	ADC3_CH7_DMA_Config();

	OSisrInstall(56, ADChandler);

/* ------------------------------------------------ */
/* Application set-up								*/

	MbxADC  = MBXopen("ADC", 5);
	MbxTime = MBXopen("Time", 5);

	ADC_SoftwareStartConv(ADC3);

/* ------------------------------------------------ */
/* Interrupts ON, the application runs				*/

	OSeint(1);

	puts("\n\n");									/* Welcome banner								*/
	puts("\n       Abassi Demo 6\n");
	puts("\n      ST STM3220G-EVAL\n");
	puts("\n      Use the trimmer\n\n");

	LCD_DisplayStringLine(LINE(0), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(1), (uint8_t *)"    Abassi Demo 6   ");
	LCD_DisplayStringLine(LINE(2), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(3), (uint8_t *)"   Use the trimmer  ");
	LCD_DisplayStringLine(LINE(4), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(5), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(6), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(7), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(8), (uint8_t *)"                    ");
	LCD_DisplayStringLine(LINE(9), (uint8_t *)"                    ");

	ADCval = 0;

	Tdigits[0] = 0;
	Tdigits[1] = 0;
	Tdigits[2] = 0;
	Tdigits[3] = 0;

	Str[0]     = ' ';
	Str[1]     = ' ';
	Str[2]     = ' ';

	for (;;) {
		EVTwait(0x0000, 0xFFFF, -1);				/* A&E Waiting for a new time or ADC value		*/
		while (0 == MBXget(MbxTime, &Msg, 0)) {		/* Empty the mailbox with the running time		*/
			Time = (unsigned int)Msg;				/* The ISR limits the time to < 3600			*/
			Tdigits[0] = Time       / 600;			/* Minutes MS digit								*/
			Time      -= Tdigits[0] * 600; 
			Tdigits[1] = Time       / 60;			/* Minutes LS digit								*/
			Time      -= Tdigits[1] * 60; 
			Tdigits[2] = Time       / 10;			/* Seconds MS digit								*/
			Time      -= Tdigits[2] * 10; 
			Tdigits[3] = Time;						/* Seconds LS digit								*/
		}
			
		while(0 == MBXget(MbxADC, &Msg, 0)) {		/* Always completely mpty the mailbox			*/
			ADCval = (unsigned int)Msg;				/* Memo the ADC value 							*/
		}

		ii = (int)((double)ADCval/40.95);

		sprintf(&Str[3], "[%d%d:%d%d] ADC:%u%%       ", Tdigits[0], Tdigits[1], Tdigits[2], Tdigits[3],
		        ii);
		printf("%s\r", &Str[3]);

		LCD_SetColors(FG_COLOR, BG_COLOR);
		LCD_DisplayStringLine(LINE(6), (unsigned char *)&Str[0]);

		ii = 100-ii;								/* The library uses inverted axis				*/
		LCD_SetColors(LCD_COLOR_GREY, LCD_COLOR_GREY);
		for (jj=(80*LCD_PIXEL_HEIGHT)/100 ; jj<(95*LCD_PIXEL_HEIGHT)/100 ; jj++) {
			LCD_DrawLine((uint16_t)jj, (uint16_t)((((ii))*LCD_PIXEL_WIDTH)/100),
			             (uint16_t)(((ii)*LCD_PIXEL_WIDTH+99)/100), LCD_DIR_HORIZONTAL);
		}

		LCD_SetColors(FG_COLOR, FG_COLOR);
		for (jj=(80*LCD_PIXEL_HEIGHT)/100 ; jj<(95*LCD_PIXEL_HEIGHT)/100 ; jj++) {
			LCD_DrawLine((uint16_t)jj, (uint16_t)(LCD_PIXEL_WIDTH-1), 
			            (uint16_t)(((100-ii)*LCD_PIXEL_WIDTH)/100), LCD_DIR_HORIZONTAL);
		}
	}
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* Idle Task																						*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

void IdleTask(void)
{
	for(;;);										/* Idle is a do nothing task					*/
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* RTOS Timer call back function																	*/
/*																									*/
/* Here we use the macro OS_TICK_PER_SEC to get the XXX led to toggle once every second				*/
/* The LED is not toggle here; instead FctHI gets awaken by posting SemRed							*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

void TIMcallBack(void)
{
static int SecCnt  = 0;								/* Conter to incrm Seconds once per second		*/
static int Seconds = 0;								/* RTC cumulative seconds						*/

	ADC_SoftwareStartConv(ADC3);				/* Start an AD conversion							*/

	SecCnt++;
	if (SecCnt >= OS_TICK_PER_SEC) {				/* Time to add one more second					*/
		Seconds++;
		if (Seconds >= 3600) {						/* The maximum display value is 59:59			*/
			Seconds = 0;
		}
		SecCnt = 0;
		MBXput(MbxTime, (intptr_t)Seconds, 0);		/* Send to the ADC task the new time in seconds	*/
		EVTset(A_E, 0x1);
	}

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* ADC interrupt handler																			*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */


void ADChandler(void)
{
static unsigned int  ADCavg = 0;
static int           ADCcnt = 0;


	ADCavg += (unsigned int)ADC3ConvertedValue;
	ADCcnt++;
	if (ADCcnt >= 8) {								/* Averaging 8 times							*/
		ADCavg = (ADCavg+4) >> 3;					/* Rounding and /8								*/
		MBXput(MbxADC, (intptr_t)ADCavg, 0);		/* Send ADC value to the A&E thriugh a mailbox	*/
		EVTset(A_E, 0x1);							/* Inform A&E there is soemting in one mailbox	*/
		ADCavg = 0;									/* Restart the averaging						*/
		ADCcnt = 0;
	}

    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);  

	return;
}

/* ------------------------------------------------------------------------------------------------ */
void ADC3_CH7_DMA_Config(void)
{
ADC_InitTypeDef       ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef       DMA_InitStructure;
GPIO_InitTypeDef      GPIO_InitStructure;
NVIC_InitTypeDef      NVIC_InitStructure;

	/* Enable ADC3, DMA2 and GPIO clocks ****************************************/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOF, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

	/* DMA2 Stream0 channel2 configuration **************************************/
	DMA_InitStructure.DMA_Channel            = DMA_Channel_2;  
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
	DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&ADC3ConvertedValue;
	DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralToMemory;
	DMA_InitStructure.DMA_BufferSize         = 1;
	DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Disable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;
	DMA_InitStructure.DMA_Priority           = DMA_Priority_High;
	DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;         
	DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_HalfFull;
	DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
	DMA_Init(DMA2_Stream0, &DMA_InitStructure);

	DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);

	DMA_Cmd(DMA2_Stream0, ENABLE);

	NVIC_InitStructure.NVIC_IRQChannel                   = DMA2_Stream0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
	NVIC_Init(&NVIC_InitStructure);     

	/* Configure ADC3 Channel7 pin as analog input ******************************/
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_Init(GPIOF, &GPIO_InitStructure);

	/* ADC Common Init **********************************************************/
	ADC_CommonInitStructure.ADC_Mode             = ADC_Mode_Independent;
	ADC_CommonInitStructure.ADC_Prescaler        = ADC_Prescaler_Div2;
	ADC_CommonInitStructure.ADC_DMAAccessMode    = ADC_DMAAccessMode_Disabled;
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
	ADC_CommonInit(&ADC_CommonInitStructure);

	/* ADC3 Init ****************************************************************/
	ADC_InitStructure.ADC_Resolution           = ADC_Resolution_12b;
	ADC_InitStructure.ADC_ScanConvMode         = DISABLE;
	ADC_InitStructure.ADC_ContinuousConvMode   = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
	ADC_InitStructure.ADC_ExternalTrigConv     = ADC_ExternalTrigConv_T1_CC1;
	ADC_InitStructure.ADC_DataAlign            = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfConversion      = 1;
	ADC_Init(ADC3, &ADC_InitStructure);

	/* ADC3 regular channel7 configuration *************************************/
	ADC_RegularChannelConfig(ADC3, ADC_Channel_7, 1, ADC_SampleTime_3Cycles);

	/* Enable DMA request after last transfer (Single-ADC mode) */
	ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);

	/* Enable ADC3 DMA */
	ADC_DMACmd(ADC3, ENABLE);

	/* Enable ADC3 */
	ADC_Cmd(ADC3, ENABLE);

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/*																									*/
/* UART functions needed by the Peripheral library to access the UART								*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

#if !defined(_write_r)
_ssize_t _write_r (struct _reent *rreenn, int fd, const void *vbuf, size_t len)
{
const char *buf;
int   size;

	size = len;
	buf  = vbuf;
	while (size > 0) {
		if (*buf == '\n') {
			while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TXE) == RESET);
			USART_SendData(EVAL_COM1, '\r');
		}
		while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TXE) == RESET);
		USART_SendData(EVAL_COM1, *buf);
		buf++;
		size--;
	}

	return(len);
}
#endif
/* ------------------------------------------------------------------------------------------------ */

#if !defined(_read_r)
_ssize_t  _read_r(struct _reent *rreenn, int fd, void *vbuf, size_t size)
{
int len;
char *buf;

	buf = vbuf;
	len = 1;
	while(USART_GetFlagStatus(EVAL_COM1, USART_FLAG_RXNE) == RESET);
	*buf = USART_ReceiveData(EVAL_COM1) & 0xFF;
	if(EVAL_COM1->SR & (USART_FLAG_ORE | USART_FLAG_PE | USART_FLAG_FE) ) {
		len = 0;
	}
	return(len);
}
#endif

/* EOF */
