DMA on STM32F4 doesn't work, is my configuration wrong? - configuration

I'm working on a project for a digital filter, see figure below. I have timer 3 triggering the ADC at 40kHz, the ADC should then make a sample and when its conversion is done it should trigger the DMA. The DMA should then move the converted value from the ADC peripheral memory to a memory address. Timer 3 works fine, however the DMA_IRQHandler code doesn't seem to work.
Does anybody know if my configuration of the DMA or the ADC is wrong? My code is depicted below.
Many thanks!
void timer_init (void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef timerInitStructure;
timerInitStructure.TIM_Prescaler = 0;
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = 1050*2; // Sample frequentie, 40kHz
timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
timerInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &timerInitStructure);
TIM_Cmd(TIM3, ENABLE);
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);
}
void timer_interrupt_init (void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the timer global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init (&NVIC_InitStructure);
//NVIC_SetPriority(TIM3_IRQn, 2);
}
void timer_start (void)
{
TIM_Cmd (TIM3, ENABLE);
}
void timer_stop (void)
{
TIM_Cmd (TIM3, DISABLE);
}
void timer_interrupt_enable (void)
{
/*
* It is important to clear any pending interrupt flags since the timer
* has been free-running since we last used it and that will generate
* interrupts on overflow even though the associated interrupt event has
* not been enabled.
*/
TIM_ClearITPendingBit (TIM3, TIM_IT_Update);
/* put the counter into a known state */
TIM_SetCounter (TIM3, 0);
TIM_ITConfig (TIM3, TIM_IT_Update, ENABLE);
}
void timer_interrupt_disable (void)
{
TIM_ITConfig (TIM3, TIM_IT_Update, DISABLE);
}
void TIM3_IRQHandler (void)
{
if (TIM_GetITStatus (TIM3, TIM_IT_Update) != RESET)
{
//GPIO_ToggleBits(GPIOD, GREEN_PIN); // For checking the timer frequency with a scope
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
void adc_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); // Enable the clock for the ADC peripheral
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);// Enable the clock for the GPIO peripheral
// Configure GPIO PC1 to analog mode
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// Configure the common adc parameters
ADC_CommonInitTypeDef ADC_CommonInitStruct;
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStruct);
// Configure the specific adc parameters
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; // ADC gets triggered by timer 3
ADC_InitStruct.ADC_NbrOfConversion = 1; // single conversion
ADC_Init(ADC2, &ADC_InitStruct);
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
ADC_DMACmd(ADC2, ENABLE);
ADC_Cmd(ADC2, ENABLE);
}
void DMA_Initialize(void)
{
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
/* Initialise DMA */
DMA_StructInit(&DMA_InitStructure);
DMA_DeInit(DMA2_Stream3); //Set DMA registers to default values
/* config of DMAC */
DMA_InitStructure.DMA_Channel = DMA_Channel_1; /* This channel is linked to ADC2*/
DMA_InitStructure.DMA_BufferSize = 1; /* Size in words of the buffer where the adc sample value gets stored */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; /* direction */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; /* no FIFO */
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /* here you van select normal mode or circular buffer */
DMA_InitStructure.DMA_Priority = DMA_Priority_High; /* here you can select the priority of the dma stream. */
/* config of memory */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_value; /* target addr */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //DMA_MemoryDataSize_Word /* 16 bit */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_Init(DMA2_Stream3, &DMA_InitStructure); /* See Table 20 for mapping */
DMA_Cmd(DMA2_Stream3, ENABLE);
DMA_ITConfig(DMA2_Stream3,DMA_IT_TC, ENABLE);
}
void DMA2_Stream3_IRQHandler()
{
if(DMA_GetITStatus(DMA2_Stream3, DMA_IT_TCIF3) != RESET)
{
DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TCIF3);
GPIO_ToggleBits(GPIOD, RED_PIN);
}
}

It looks like the NVIC configuration for DMA is missing. I guess something like this before DMA_ITConfig(DMA2_Stream3,DMA_IT_TC, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, ENABLE);
also, call this part before DMA_Cmd(DMA2_Stream3, ENABLE);

Related

Can I send tone() function wirelessly?

I have a simple RPM Simulator (opensource) that generates values through the tone() function.
I need to send the RPM wirelessly through an nrf24l01 to a second Arduino that uses the RPM as a shiftlight, both come from chippernut.
The tone() function only sends to the pin, trying to read the values did not work.
How can i get the value of x (RPM) after it leaves the tone function?
I have tried reading it through analogRead, digitalRead, BitRead, tried printing the value of x which stays constant, to no avail, and it updates very slowly if it reads the output pin.
This is the code:
float RPM_MIN = 2500;
float RPM_MAX = 8000;
int Accel_Rate = 20;
float pulses_per_rev = 2.0; // make sure to keep the decimal
boolean accel = false;
float x;
long previousMillis = 0;
unsigned long currentMillis=0;
//float RPM_PRINT; //my addition to get a value to print
void setup() {
Serial.begin(57600);
pinMode(5, OUTPUT);
RPM_MIN = (RPM_MIN / 60);
RPM_MAX = (RPM_MAX / 60);
x = RPM_MIN;
}
void loop() {
while (accel==false){
currentMillis = millis();
if(currentMillis - previousMillis > Accel_Rate) {
previousMillis = currentMillis;
x++;
tone(5,x*pulses_per_rev);
if (x>RPM_MAX){accel=true;}
}
}
while (accel==true){
currentMillis = millis();
if(currentMillis - previousMillis > Accel_Rate) {
previousMillis = currentMillis;
x--;
tone(5,x*pulses_per_rev);
if (x<RPM_MIN){accel=false;}
}
}
//RPM_PRINT = x*pulses_per_rev;
//RPM_PRINT = digitalRead(5);
//RPM_PRINT = analogRead(5);
//Serial.println(RPM_PRINT);
}
Expected Result is a Value between 2000-8000 that is constantly changing
actual result is 1/0 or 81,33 or 4,1 or 900-980 updating once every few seconds.
How can I solve?

How to transform only the input signal source of an existing Arduino FFT source

My question is one.
1. I want to FFT the unstable input voltage through the Arduino.
How do I transform from an existing Arduino FFT source?
I'm an Arduino starter.
Please give me a detailed answer.
/*
fft_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fft library.
it takes in data on ADC0 (Analog0) and processes them
with the fft. the data is sent out over the serial
port at 115.2kb.
*/
#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#include <FFT.h> // include the library
void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
while(1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_window(); // window the data for better frequency respons
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
fft_mag_log(); // take the output of the fft
sei();
Serial.println("start"); // header send
for (byte i = 0 ; i < FFT_N ; i+=2) {
Serial.write(fft_input[i]); // send out the real part
Serial.write(fft_input[i+1]); // send out the imaginary part
}
}
}

Does calling a CUDA kernel multiple times affect execution speed?

I am trying to measure the performance difference of a GPU between allocating memory using 'malloc' in a kernel function vs. using pre-allocated storage from 'cudaMalloc' on the host. To do this, I have two kernel functions, one that uses malloc, one that uses a pre-allocated array, and I time the execution of each function repeatedly.
The problem is that the first execution of each kernel function takes between 400 - 2500 microseconds, but all subsequent runs take about 15 - 30 microseconds.
Is this behavior expected, or am I witnessing some sort of carryover effect from previous runs? If this is carryover, what can I do to prevent it?
I have tried putting in a kernel function that zeros out all memory on the GPU between each timed test run to eliminate that carryover, but nothing changed. I have also tried reversing the order in which I run the tests, and that has no effect on relative or absolute execution times.
const int TEST_SIZE = 1000;
struct node {
node* next;
int data;
};
int main() {
int numTests = 5;
for (int i = 0; i < numTests; ++i) {
memClear();
staticTest();
memClear();
dynamicTest();
}
return 0;
}
__global__ void staticMalloc(int* sum) {
// start a linked list
node head[TEST_SIZE];
// initialize nodes
for (int j = 0; j < TEST_SIZE; j++) {
// allocate the node & assign values
head[j].next = NULL;
head[j].data = j;
}
// verify creation by adding up values
int total = 0;
for (int j = 0; j < TEST_SIZE; j++) {
total += head[j].data;
}
sum[0] = total;
}
/**
* This is a test that will time execution of static allocation
*/
int staticTest() {
int expectedValue = 0;
for (int i = 0; i < TEST_SIZE; ++i) {
expectedValue += i;
}
// host output vector
int* h_sum = new int[1];
h_sum[0] = -1;
// device output vector
int* d_sum;
// vector size
size_t bytes = sizeof(int);
// allocate memory on device
cudaMalloc(&d_sum, bytes);
// only use 1 CUDA thread
dim3 blocksize(1, 1, 1), gridsize(1, 1, 1);
Timer runTimer;
int runTime = 0;
// check dynamic allocation time
runTime = 0;
runTimer.start();
staticMalloc<<<gridsize, blocksize>>>(d_sum);
runTime += runTimer.lap();
h_sum[0] = 0;
cudaMemcpy(h_sum, d_sum, bytes, cudaMemcpyDeviceToHost);
cudaFree(d_sum);
delete (h_sum);
return 0;
}
__global__ void dynamicMalloc(int* sum) {
// start a linked list
node* headPtr = (node*) malloc(sizeof(node));
headPtr->data = 0;
headPtr->next = NULL;
node* curPtr = headPtr;
// add nodes to test cudaMalloc in device
for (int j = 1; j < TEST_SIZE; j++) {
// allocate the node & assign values
node* nodePtr = (node*) malloc(sizeof(node));
nodePtr->data = j;
nodePtr->next = NULL;
// add it to the linked list
curPtr->next = nodePtr;
curPtr = nodePtr;
}
// verify creation by adding up values
curPtr = headPtr;
int total = 0;
while (curPtr != NULL) {
// add and increment current value
total += curPtr->data;
curPtr = curPtr->next;
// clean up memory
free(headPtr);
headPtr = curPtr;
}
sum[0] = total;
}
/**
* Host function that prepares data array and passes it to the CUDA kernel.
*/
int dynamicTest() {
// host output vector
int* h_sum = new int[1];
h_sum[0] = -1;
// device output vector
int* d_sum;
// vector size
size_t bytes = sizeof(int);
// allocate memory on device
cudaMalloc(&d_sum, bytes);
// only use 1 CUDA thread
dim3 blocksize(1, 1, 1), gridsize(1, 1, 1);
Timer runTimer;
int runTime = 0;
// check dynamic allocation time
runTime = 0;
runTimer.start();
dynamicMalloc<<<gridsize, blocksize>>>(d_sum);
runTime += runTimer.lap();
h_sum[0] = 0;
cudaMemcpy(h_sum, d_sum, bytes, cudaMemcpyDeviceToHost);
cudaFree(d_sum);
delete (h_sum);
return 0;
}
__global__ void clearMemory(char *zeros) {
int i = threadIdx.x + blockDim.x * blockIdx.x;
zeros[i] = 0;
}
void memClear() {
char *zeros[1024]; // device pointers
for (int i = 0; i < 1024; ++i) {
cudaMalloc((void**) &(zeros[i]), 4 * 1024 * 1024);
clearMemory<<<1024, 4 * 1024>>>(zeros[i]);
}
for (int i = 0; i < 1024; ++i) {
cudaFree(zeros[i]);
}
}
The first execution of a kernel takes more time because you have to load a lots of stuff on GPU (kernel, lib etc...). To prove it, you can just measure how long it takes to launch an empty kernel and you will see that it's take some times. Try like:
time -> start
launch emptykernel
time -> end
firstTiming = end - start
time -> start
launch empty kernel
time -> end
secondTiming = end - start
You will see that the secondTiming is significantly smaller thant the firstTiming.
The first CUDA (kernel) call initializes the CUDA system transparently. You can avoid this by calling an empty kernel first. Note that this is required in e.g. OpenCL, but there you have to do all that init-stuff manually. CUDA does it for you in the background.
Then some problems with your timing: CUDA kernel calls are asynchronous. So (assuming your Timer class is a host timer like time()) currently you measure the kernel launch time (and for the first call the init-time of CUDA) not the kernel execution time.
At the very least you HAVE to do a cudaDeviceSynchronize() before starting AND stopping the timer.
You are better of using CUDA events which can exactly measure the kernel execution time and only that. Using host-timers you still include the launch-overhead. See https://devblogs.nvidia.com/parallelforall/how-implement-performance-metrics-cuda-cc/

How to make a sliding menu in cocos2dx in c++ for IOS game

I want to make a sliding menu just like the level menu in which on one screen there will be 40 sprites labelled as level 1 level 2 respectively up to 40.
At the bottom right there will be another sprite with a arrow to which when I click it should slide to other screen and show the levels 41 to 80.Please provide me with a basic concept how to use it.I will be thankful to you.
Note: I am using Xcode and ony want solution in cocos2d-x using c++
This is the way I have done this in the past...I had a game with the option for the player to select multiple space ships, 4 per page, with back/forward arrows on each page as well.
Create a CCScene derived class.
Place all your menu items, including the control arrows for ALL pages on it. You will have to space all the items so the items for the first page are on the visible part of the screen and the next group is 100% off to the right, the third group is 200% off the right, etc.
The control buttons on the scene start an action to move the layer 100% to the left (if they move right) or 100% to the right (if they move left).
All of these are attached to a single "Menu", which is what the actions are applied against. If you want, you can put the menu into a layer (so it has background that moves). This is up to you.
In the example Scene below, I just used a simple menu.
MainScene.h
#ifndef __MainScene__
#define __MainScene__
#include "cocos2d.h"
using namespace cocos2d;
class MainScene : public CCScene
{
private:
// This class follows the "create"/"autorelease" pattern.
// Private constructor.
MainScene();
CCMenu* _menu;
bool _sliding;
void MenuCallback(CCObject* sender);
void PageLeft();
void PageRight();
void SlidingDone();
protected:
// This is protected so that derived classes can call it
// in their create methods.
bool init();
private:
void CreateMenu();
public:
static MainScene* create();
~MainScene();
virtual void onEnter();
virtual void onExit();
virtual void onEnterTransitionDidFinish();
virtual void onExitTransitionDidStart();
};
#endif /* defined(__MainScene__) */
MainScene.cpp
#include "MainScene.h"
#define ARROW_LEFT (-1)
#define ARROW_RIGHT (-2)
#define MENU_ITEMS_ACROSS 4
#define MENU_ITEMS_DOWN 5
#define MENU_ITEMS_PAGE (MENU_ITEMS_ACROSS*MENU_ITEMS_DOWN)
#define MENU_ITEMS_TOTAL 50
#define MENU_PAGES ((MENU_ITEMS_TOTAL/MENU_ITEMS_PAGE)+1)
#define MENU_FRACTION (ccp(0.8,0.8))
#define MENU_ANCHOR (ccp(0.5,0.5))
#define SLIDE_DURATION 1.0
MainScene::MainScene() :
_menu(NULL)
_sliding(false)
{
}
MainScene::~MainScene()
{
}
static CCPoint CalculatePosition(int itemNum)
{
CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
float Xs = scrSize.width;
float Ys = scrSize.height;
int gRows = MENU_ITEMS_DOWN;
int gCols = MENU_ITEMS_ACROSS;
int gBins = gRows*gCols;
float Xb = MENU_FRACTION.x*Xs/gCols;
float Yb = MENU_FRACTION.y*Ys/gRows;
float Xa = MENU_ANCHOR.x * Xs;
float Ya = MENU_ANCHOR.y * Ys;
int page = itemNum / gBins;
int binCol = itemNum % gCols;
int binRow = (itemNum-page*gBins) / gCols;
float xPos = binCol * Xb + Xb/2 + Xa - MENU_FRACTION.x*Xs/2 + page * Xs;
float yPos = Ya - binRow*Yb - Yb/2 + MENU_FRACTION.y * Ys/2;
CCPoint pos = ccp(xPos,yPos);
return pos;
}
void MainScene::CreateMenu()
{
if(_menu == NULL)
{
CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
_menu = CCMenu::create();
_menu->setPosition(ccp(0,0));
addChild(_menu);
CCMenuItemFont* pItem;
CCPoint position;
// Create the next/back menu items.
for(int page = 0; page < MENU_PAGES; page++)
{
// Create the Back/Forward buttons for the page.
// Back arrow if there is a previous page.
if(page > 0)
{
pItem = CCMenuItemFont::create("Back", this, menu_selector(MainScene::MenuCallback));
pItem->setTag(ARROW_LEFT);
position = ccp(page*scrSize.width + scrSize.width*0.1,scrSize.height*0.1);
pItem->setPosition(position);
pItem->setFontSize(35);
pItem->setFontName("Arial");
_menu->addChild(pItem);
}
if(page < (MENU_PAGES-1))
{
pItem = CCMenuItemFont::create("Next", this, menu_selector(MainScene::MenuCallback));
pItem->setTag(ARROW_RIGHT);
position = ccp(page*scrSize.width + scrSize.width*0.9,scrSize.height*0.1);
pItem->setPosition(position);
pItem->setFontSize(35);
pItem->setFontName("Arial");
_menu->addChild(pItem);
}
}
// Create the actual items
for(int idx = 0; idx < MENU_ITEMS_TOTAL; idx++)
{
char buffer[256];
sprintf(buffer,"Item #%d",idx);
pItem = CCMenuItemFont::create(buffer, this, menu_selector(MainScene::MenuCallback));
pItem->setFontSize(35);
pItem->setFontName("Arial");
pItem->setTag(idx);
position = CalculatePosition(idx);
pItem->setPosition(position);
_menu->addChild(pItem);
}
}
}
bool MainScene::init()
{
return true;
}
MainScene* MainScene::create()
{
MainScene *pRet = new MainScene();
if (pRet && pRet->init())
{
pRet->autorelease();
return pRet;
}
else
{
CC_SAFE_DELETE(pRet);
return NULL;
}
}
void MainScene::onEnter()
{
CCScene::onEnter();
CreateMenu();
}
void MainScene::onExit()
{
CCScene::onExit();
}
void MainScene::onEnterTransitionDidFinish()
{
CCScene::onEnterTransitionDidFinish();
}
void MainScene::onExitTransitionDidStart()
{
CCScene::onExitTransitionDidStart();
}
void MainScene::SlidingDone()
{
_sliding = false;
}
void MainScene::PageLeft()
{
if(_sliding)
return;
_sliding = true;
CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
CCFiniteTimeAction* act1 = CCMoveBy::create(SLIDE_DURATION, ccp(scrSize.width,0));
CCFiniteTimeAction* act2 = CCCallFunc::create(this, callfunc_selector(MainScene::SlidingDone));
_menu->runAction(CCSequence::create(act1,act2,NULL));
}
void MainScene::PageRight()
{
if(_sliding)
return;
_sliding = true;
CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
CCFiniteTimeAction* act1 = CCMoveBy::create(SLIDE_DURATION, ccp(-scrSize.width,0));
CCFiniteTimeAction* act2 = CCCallFunc::create(this, callfunc_selector(MainScene::SlidingDone));
_menu->runAction(CCSequence::create(act1,act2,NULL));
}
void MainScene::MenuCallback(CCObject* sender)
{
// This is a very contrived example
// for handling the menu items.
// -1 ==> Left Arrow
// -2 ==> Right Arrow
// Anything else is a selection
CCMenuItem* pMenuItem = (CCMenuItem*)sender;
switch(pMenuItem->getTag())
{
case ARROW_LEFT:
PageLeft();
break;
case ARROW_RIGHT:
PageRight();
break;
default:
CCLOG("Got Item %d Pressed",pMenuItem->getTag());
break;
}
}
Note The formulas for getting the items spread across several pages can be a little tricky. There is a notion of "Screen fraction", which is how much the grid of items takes up on the page. There is also the notion of "menu anchor", which where on the page you want the grid to be.
Some screen shots
or you can do it the modern way with less code!!
// you have to include this header to use the ui classes
#include "ui/CocosGUI.h"
using namespace ui;
#define COLS 4
#define ROWS 4
#define ITEMS_PER_PAGE (ROWS * COLS)
#define TOTAL_PAGES_NUM 10
#define MENU_PADDING (Vec2(0.8,0.8))
#define MENU_ANCHOR (Vec2(0.5,0.5))
static Vec2 calcPosition(int itemNum)
{
Size scrSize = Director::getInstance()->getWinSize();
float Xs = scrSize.width;
float Ys = scrSize.height;
float Xb = MENU_PADDING.x*Xs / COLS;
float Yb = MENU_PADDING.y*Ys / ROWS;
float Xa = MENU_ANCHOR.x * Xs;
float Ya = MENU_ANCHOR.y * Ys;
int page = itemNum / ITEMS_PER_PAGE;
int binCol = itemNum % COLS;
int binRow = (itemNum - page * ITEMS_PER_PAGE) / COLS;
float xPos = binCol * Xb + Xb / 2 + Xa - MENU_PADDING.x*Xs / 2 + page * Xs;
float yPos = Ya - binRow*Yb - Yb / 2 + MENU_PADDING.y * Ys / 2;
return Vec2(xPos, yPos);
}
//init method
// pageView is the container that will contain all pages
auto pageView = PageView::create();
pageView->setContentSize(winSize);
//if you want pages indicator just uncomment this
//pageView->setIndicatorEnabled(true);
//pageView->setIndicatorPosition(some position);
//pageView->setIndicatorSelectedIndexColor(some Color3B);
for (int i = 0; i < TOTAL_PAGES_NUM; i++) {
auto layout = Layout::create();
layout->setContentSize(winSize);
// give each page a different random color
int r = rand() % 200;
int g = rand() % 200;
int b = rand() % 200;
auto bg = LayerColor::create(Color4B(Color3B(r, g, b)), winSize.width, winSize.height);
layout->addChild(bg, 0);
// populate each single page with items (which are in this case labels)
for (int i = 0; i < ITEMS_PER_PAGE; i++) {
auto label = LabelTTF::create(StringUtils::format("item %i", (i + 1)), "Comic Sans MS", 15);
Vec2 pos = calcPosition(i);
label->setPosition(pos);
layout->addChild(label, 1);
}
pageView->addPage(layout);
}
this->addChild(pageView);
I’ve modified existing one and uploaded in github. Here is the link:
GitHub Link to SlidingMenu
You may find it helpful. You can directly add it into your game.

how to initialize seed value once in mersenne twister and use multiple times to get different random numbers each time

I am unable to get different random numbers from the MT,having seed with a fixed value(not changing as suggested by the testers). But when i call the same function twice in a program, it shows different values, but it don't randomize values even if i call the program multiple times.I don't understand where i am lagging behind.
Please suggest me on this
Below is the code pasted from mine .asc file(related to flash media server)
main.asc
load(shuffle.asc);
application.onAppStart=function()
{
trace("Application Started");
};
application.onConnect=function(client,name)
{
shuffledNumbers();
}
shuffle.asc
var gen_random;
function shuffledeck()
{
trace("shufledeck");
gen_random = new Array();
gen_random= new Array();
for(i=0;i<1000;i++)
{
gen_random[i]=genrand_int32();
}
trace("gen_random: "+gen_random); // HERE WE CAN SEE THE RANDOMLY GENERATED NUMBERS . THE PROBLEM: EVERYTIME I AM GETTING THE SAME RANDOM GENERATED VALUES.
}
var N = 624;
var M = 397;
var MATRIX_A = 0x9908b0df; /* constant vector a */
var UPPER_MASK = 0x80000000; /* most significant w-r bits */
var LOWER_MASK = 0x7fffffff; /* least significant r bits */
var mt =[]; /* the array for the state vector */
var mti ;
var seed ;
var returnLength ;
var maxSize ;
var returnArray = new Array();
/* initializes mt[N] with a seed */
function init_genrand($seed)
{
mt[0]= $seed & 0xffffffff;
for (mti=1; mti<N; mti++) {
mt[mti] = (1812433253 * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
mt[mti] &= 0xffffffff;
/* for >32 bit machines */
}
}
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
// void init_by_array(unsigned long init_key[], int key_length)
/* generates a random number on [0,0xffffffff]-interval */
function genrand_int32()
{
var y ;
var mag01 =[0x0, MATRIX_A];
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N)
{
/* generate N words at one time */
var kk ;
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(15475454); /* a default initial seed is used */
for (kk=0;kk<N-M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
}
for (;kk<N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1];
}
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
mti = 0;
}
y = mt[mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680;
y ^= (y << 15) & 0xefc60000;
y ^= (y >> 18);
// trace("y: "+y);
return y;
}
/* generates a random number on [0,0x7fffffff]-interval */
function genrand_int31()
{
return (genrand_int32()>>1);
}
Any help will be appriciated
PS: I have tried to convince them, by reseeding the int_genrand() function, and getting the output but, it compromises the predictability of randomness itseems.
If you are attempting to shuffle a deck of cards, I have found this function to be useful:
function fisherYates (myArray) {
var i = myArray.length;
while ( i-- ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tempi = myArray[i];
var tempj = myArray[j];
myArray[i] = tempj;
myArray[j] = tempi;
}
}
usage:
myArray = [1,2,3,4,5];
fisherYates(myArray);